iTranslated by AI
The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
😺
CSS Strategies and Component Classification in Component-Based Development: My Personal Approach
- I feel like the typical CSS know-how specific to component-based development in React or Svelte doesn't really apply.
- I posted this on Twitter and it got a good response, so I'll summarize it here in my own way.
- Markup engineers sometimes tell me that the management unit of a React Component and the management policy of layout as CSS are different, but I ignore such talk and make them match completely. That's just the nature of how I develop.
Component Classification
- Logic Components
- Layout Components
- Block Components
- Inline Components
Definitions
- Logic Components
- Handle only data processing such as Providers or hooks, and pass data to children.
- They do not have any CSS or DOM presence.
- Layout Components
- A layout component has multiple child block components (or slots), and its sole responsibility is to decide the placement of those child block components.
- Layout components other than the root are basically
width: 100%, height: 100%; margin: 0; padding: 0; box-sizing: border-box;withdisplay: gridordisplay: flex. Grid is recommended. - A layout component divides its own area using
flex,grid, etc. - The number of block components that can be placed in each divided area is 1 or 0.
- Responsive implementation is also handled here.
- Block Components
- A block component is an element that fills the area provided by the layout.
- The root element of a block component is
width: 100%; height: 100%; margin: 0; padding: 0; box-sizing: border-box; display: flex;. - The interior of a block component consists of either a single layout component or multiple inline components.
- Inline Components
- Elements that do not have a fixed height or width, where size is determined by their own content.
- Block components or layout components wrapped in a fixed-size container element with specific width and height are treated as inline components.
- Exceptional Treatment
- In my experience, when the data and DOM structure are tightly coupled, such as with DnD (Drag and Drop), it is impossible or difficult to separate logic components from everything else.
- If the service has an application-like layout, the root element of the layout component is often
width: 100vw; height: 100vh;. In traditional vertically-expanding services, parts of the layout near the root useheight: auto; overflow: auto;.
As a result, it becomes a repetition of Layout and Block, such as Root => Layout => Block => Inline or Layout => Block => ...
Sample
- Styles are written inline for explanation purposes. (Since assuming a specific CSS framework would require its own explanation...)
- I wrote this casually for explanatory purposes, so while I prioritized code readability, I haven't actually checked what gets rendered.
// Logic Component
const DataContext = createContext<{ value: number }>({ value: 0 });
function RootProvider(props: {children: React.ReactElement}) {
return <DataContext.Provider value={{ value: 1 }}>
{props.children}
</DataContext.Provider>;
}
// Layout Component
function RootLayout(props: {
header: React.ReactElement;
content: React.ReactElement;
footer: React.ReactElement;
}) {
return <div style={{
width: "100vw",
height: "100vh",
overflow: "hidden",
display: "grid",
gridTemplateAreas: `
'header'
'content'
'footer'
`,
gridTemplateColumns: "1fr",
gridTemplateRows: "100px 1fr 300px"
}}>
<div style={{gridArea: "header"}}>{props.header}</div>
<div style={{gridArea: "content"}}>{props.content}</div>
<div style={{gridArea: "content"}}>{props.footer}</div>
</div>
}
// Inline Component
function Title() {
return <div>Hello, Example</div>;
}
// Block Component
function HeaderBlock() {
return <div style={{
width: "100%",
height: "100%",
margin: "0",
padding: "0",
display: "flex",
}}>
Header
</div>;
}
// Block Component
function ContentBlock() {
return <div style={{
width: "100%",
height: "100%",
margin: "0",
padding: "0",
display: "flex",
}}>
<Title />
Content~~~
</div>;
}
// Block Component
function FooterBlock() {
return <div style={{
width: "100%",
height: "100%",
margin: "0",
padding: "0",
display: "flex",
}}>
Footer
</div>;
}
// Root Component
function App() {
return <RootProvider>
<RootLayout
header={<HeaderBlock />}
content={<ContentBlock />}
footer={<FooterBlock />}
/>
</RootProvider>
}
Benefits
- The type of component is naturally categorized based on which CSS properties are written.
- Block components are always treated as
width: 100%, height: 100%, so any block is interchangeable. - By separating layout and block, the design is resilient to changes in element placement, and implementing responsive design or multiple display modes is easy.
- Since the height is predetermined for most elements, it is friendly for skeleton screen implementation and critical rendering path optimization.
Drawbacks
- It is difficult to maintain a consistent height inheritance policy for liquid layouts.
- Block components can easily overflow if you're not careful.
- It can hardly be called a conventional (web production) style.
Discussion
記事、読みました!
記事の冒頭にある「コンポーネントの種類リスト」が興味深かったです。
この4つは、mizchiさん流の分類方法なのでしょうか。「自分ではこういう名称で分けている」がまとまっている方は、一緒に仕事をする際にありがたいですね。
CSSデザインについては、私もWebアプリ等を趣味レベルで作るのですが「とにかくまずはgridレイアウト」で色々なんとかなる、と感じていますw 具体的にはCSSファイルの先頭に * {display: grid;} 書いてるくらいw