Reusing Styles
A guide to reusing styles and code de-duplication.
Overview
As the styles grow, the class name combinations and the same design patterns appear over and over again in the code. To improve development efficiency and maintain design consistency, you should reuse or access them in some way.
This guide also provides specialized solutions tailored for frameworks.
Abstracting styles
As usual, you can split the styles into multiple files for management. When the project is small in scale, you don't necessarily have to insist on splitting style files.
🗂️ styles|-- 📄 button.ts`-- 📄 card.ts📄 master.css.ts
Create button styles
Let's implement a rich button.
import type { Config } from '@master/css' export default { styles: { btn: { '': 'center-content inline-flex font:semibold outline-offset:-1', 'xs': 'font:12 h:6x px:2x px:3x.rounded r:4', 'sm': 'font:12 h:8x px:3x px:4x.rounded r:6', 'md': 'font:14 h:10x px:4x px:5x.rounded r:6', 'lg': 'font:16 h:12x px:5x px:6x.rounded r:8', 'xl': 'font:16 h:14x px:6x px:7x.rounded r:10' } }} as Config
Extend them uniformly in the master.css.ts entry file.
import type { Config } from '@master/css'import button from './styles/button' export default { extends: [ button ]} as Config
To apply the button sizes.
<button class="btn btn-xs …">Submit</button><button class="btn btn-sm …">Submit</button><button class="btn btn-md …">Submit</button><button class="btn btn-lg …">Submit</button><button class="btn btn-xl …">Submit</button>
To apply the button sizes that are finely tuned for rounded styles.
<button class="btn btn-xs rounded …">Submit</button><button class="btn btn-sm rounded …">Submit</button><button class="btn btn-md rounded …">Submit</button><button class="btn btn-lg rounded …">Submit</button><button class="btn btn-xl rounded …">Submit</button>
To design a scalable style, you should ensure the single responsibility of class composition; otherwise, you may end up using a lot of !important
to override rules or the @preset
layer to lower default styles, ultimately leading to chaotic styles.
Create common variables and styles
We define variables and modes to create tokens supporting light/dark modes in advance. This not only simplifies template markup but also reduces CSS rule output.
import type { Config } from '@master/css' export default { variables: { yellow: { ring: { '@light': '$(black)/.1', '@dark': '$(white)/.3' } }, touch: { yellow: { '@light': '$(yellow-30)', '@dark': '$(yellow-40)' } }, text: { 'yellow-contrast': { '@light': '$(yellow-90)', '@dark': '$(yellow-95)' } } }, styles: { yellow: 'bg:yellow fg:yellow-contrast outline:1|yellow-ring', touch: { yellow: 'bg:touch-yellow:hover' } },} as Config
- Variables
yellow-ring
is an outline color that complements a yellow background.touch-yellow
is a background color on hover.text-yellow-contrast
is a contrasting color fine-tuned against a yellow background.
- Styles
.yellow
sets a background, foreground and outline style for a yellow theme..yellow-touch
sets a background, foreground and outline style for a yellow theme interaction.
<button class="btn btn-md yellow touch-yellow">Submit</button>
Componentization
In addition to styles, we provide a CSS-in-JS style utility, Master Styled, to help you create a component with classes in one line. It supports Vanilla js, React, and Vue.
🗂️ components|-- 📄 Button.tsx`-- 📄 Card.tsx📄 master.css.ts
Create a button component
You can define type-safe styles and corresponding classes for style properties.
import styled from '@master/styled.react' const sizes = { xs: 'font:12 h:6x …', sm: 'font:12 h:8x …', md: 'font:14 h:10x …', lg: 'font:16 h:12x …', xl: 'font:16 h:14x …'} declare type Props = { $size: keyof typeof sizes disabled?: boolean} const Button = styled.button<Props>('inline-flex font:semibold', { $size: sizes, disabled: 'opacity:.5'}) Button.defaultProps = { $size: 'md'} export default Button
To use the button component.
<Button $size="sm" disabled>Submit</Button>
Rendered as:
<button class="inline-flex font:semibold font:12 h:8x … opacity:.5">Submit</button>
However, if the component involves richer implementations such as loading
, you should wrap it with a functional component.
Create a block-scoped component
styled
operates on an element basis, unlike global styles mentioned above, and you can declare it within a functional component or at the top level.
Create a reusable section component specific to a marketing page.
import styled from '@master/styled.react' export default function Page() { const Section = styled.section`bg:slate-90 text:white p:15x|20x` return ( <> <section className="bg:slate-90 text:white p:15x|20x">...</section> <section className="bg:slate-90 text:white p:15x|20x">...</section> <Section>...</Section> <Section>...</Section> ... </> )}
This is useful for block-specific style reuse, rather than creating styles['home-section']
which may pollute global styles or cause name collisions.
Summary
- Moderately abstracting styles make design easier to manage and maintain consistency, but it doesn't mean that all styles should be abstracted.
- Only abstract styles that have the potential for reuse, rather than naming them simply for brevity or naming's sake.
- A good CSS structure combines abstract classes and utility classes — don’t get hung up on specific approaches.