What is the modular way of handling the following scenario: an app has general styles for all heading tags (h1, h2, h3, etc.). A specific component, Widget.jsx, may use any of these headings, but has special styling for h1 tags. In the "olden" days of CSS, I would have handled this would have been handled by inheritance in (likely) a single stylesheet. E.g.
.h1 { font-size: 3rem; /* more styles */ }
.h2 { font-size: 2.5rem; /* more styles */ }
...
.Widget--h1 { font-size: 1.5rem; }
Obviously, the above doesn't fit within a modular approach to CSS, but I'm not sure how to accomplish the above scenario modularly. What follows is my initial attempt at solving the problem.
Widget.jsx
import React from "react";
import CSSModules from "react-css-modules";
import styles from "./_widget.less";
@CSSModules( styles )
export default class Widget extends React.Component {
render () {
return (
<div>
<h1 styleName="h1">Chewbacca</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Totam blanditiis, explicabo illo dignissimos vitae voluptatibus est itaque fuga tenetur, architecto recusandae dicta dolorem. Velit quidem, quos dignissimos unde, iste amet?</p>
<h2 styleName="h2">The "Walking Carpet"</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
);
}
}
_widget.less
.h1 {
composes: h1 from "atoms/text/_text.less";
font-family: "Comic Sans MS", cursive, sans-serif;
}
atoms/text/_text.less
@import (reference) "~styles/variables/_fonts.less";
/* Headings
============================= */
.h1, .h2, .h3, .h4, .h5, .h6 {
font-weight: normal;
margin-top: 0px;
margin-right: 0px;
margin-bottom: 10px;
margin-left: 0px;
}
.h1 { font-family: @primary-font; }
.h2 { font-family: @primary-font; }
.h3 { font-family: @primary-font; }
.h4 { font-family: @primary-font; }
.h5 { font-family: @primary-font; }
.h6 { font-family: @primary-font; }
It works all the way up to the point of using one of the general, unmodified classes (.h2
). Obviously, the problem is that .h2
isn't defined in _widget.less
and there is no "global" defintion for those classes (in keeping with modular CSS best practices), but I tend to think that explicitely composing the other heading classes into .h2, .h3, .h4 ...
classes isn't the answer either. E.g.
_widget.less
.h1 {
composes: h1 from "atoms/text/_text.less";
font-family: "Comic Sans MS", cursive, sans-serif;
}
.h2 { composes: h2 from "atoms/text/_text.less"; }
.h3 { composes: h3 from "atoms/text/_text.less"; }
...
Another potential solution is to @import
the general heading styles into the _widget.less
file.
_widget.less
@import @import "~atoms/text/_text.less";
.h1 {
composes: h1 from "atoms/text/_text.less";
font-family: "Comic Sans MS", cursive, sans-serif;
}
The problem with that solution is that those styles will be duplicated every time I utilize styles from _text.less
and bloat my deliverable code.
Any thoughts on how best to solve this type of problem? I'm very new to the concept of modular CSS.
In cases like this where you want to overlay a default set of classes with customisations, one way to do it is with Object.assign
:
import defaultStyles from "atoms/text/_text.less"
import widgetStyles from "./_widget.less"
const styles = Object.assign({}, defaultStyles, widgetStyles)
So now styles
contains tokens for all kinds of headings, and uses the widget override whenever available.