You've learned BEM. Your naming is correct. Your components are properly decomposed.
You think you "get" CSS, right?
Then answer this — should that CSS property go on the parent (the container) or the child (the item)? Can you explain why?
If you can't, what's missing isn't a naming convention. It's the fundamentals of CSS itself — something that comes before any design methodology.
This article lays out that foundation: the concept of property responsibility.
Why Correct Naming Still Leads to Broken Layouts
Look at these two patterns:
// Pattern A
.card-list {
display: flex;
flex-direction: column;
}
.card + .card {
margin-top: 24px;
}
.card {
padding: 16px;
}
// Pattern B
.card-list {
display: flex;
flex-direction: column;
// Parent decides spacing between children
> .card + .card {
margin-top: 24px;
}
}
.card {
padding: 16px;
}
Here, .card-list is the parent (the container) and .card is the child (the item).
Assuming .card elements are direct children, both produce the same visual result.
But in Pattern A, .card knows about its own layout position (margin-top). Change the parent, and it breaks.
Pattern B separates responsibilities — placement (margin-top) is handled by the parent, internal styling (padding) by the child.
This difference has nothing to do with naming conventions. It's about understanding CSS's layout model itself.
In Flexbox, properties are split between Container (display: flex, etc.) and Item (align-self, flex, etc.). Since margin determines the outer spacing of a child element, specifying it via the parent's child selector tends to be more consistent in practice.
The Problem with Writing CSS That "Looks Right"
Here's a pattern I see all the time. BEM naming is correct, components are reasonably decomposed — but property placement is all over the place:
- Some components write
marginon themselves; others have it specified from the parent - Container and Item properties are mixed in the same block without distinguishing roles (An element serving as both Container and Item is perfectly normal — mixing them unconsciously is what makes code unreadable)
-
paddingandmarginare jumbled together with no apparent logic
This is what happens when you write without understanding property responsibility. The output looks correct. It passes code review. But change the parent component and the layout breaks.
This isn't an individual skill issue. It's a structural problem: CSS education is too heavily weighted toward naming and component decomposition.
You perfect your TypeScript types. You learn React patterns. But are you still placing CSS properties based on gut feeling?
Even when AI coding agents write CSS, the same problem occurs. Naming and component decomposition may look reasonable, but property placement tends to be inconsistent. When the human-side criteria for CSS design are ambiguous to begin with, this is likely to happen.
That's the fundamental both humans and AI struggle with: property responsibility.
The Three Property Categories
CSS properties can be classified into three categories by responsibility:
| Category | Role | Examples | Where to Write |
|---|---|---|---|
| Container | Determines how children are arranged |
display, gap, justify-content
|
On the element itself |
| Item | Position within parent's layout |
margin, flex, order, align-self
|
In the parent's child selector (e.g., > .child) |
| Internal | The element's own appearance |
padding, font-size, color, background
|
On the element itself |
This classification reflects how CSS layout models (Flexbox, Grid) actually work. It's not specialized framework knowledge — it's CSS fundamentals (this article is an overview of the design principle; the lint rules mentioned later cover a subset of this).
Note that Item properties (align-self, flex, etc.) are applied to child elements per the CSS spec, but the key point of this approach is that the parent specifies them on the child (via > .child selectors). At boundaries where the parent can't directly select the child (slots, dynamic insertion, etc.), use a wrapper (e.g., .card-list__item) or utility class (e.g., .u-mt-24) to bridge the gap.
Just being aware of these three categories changes code structure significantly:
// Container properties → on the element itself
.card-list {
display: flex;
flex-wrap: wrap;
gap: 24px;
// Item properties → from parent to child
> .feature-card {
flex: 1 1 300px;
align-self: flex-start;
}
}
// Internal properties → on the element itself
.feature-card {
padding: 16px;
background: white;
border-radius: 8px;
}
Once you can see this classification, you can tell whether property placement in someone else's code is intentional:
-
marginspecified from the parent's child selector → understands responsibility -
marginwritten on the child component itself → responsibility is unclear - Container and Item properties are separated → understands CSS layout models
-
display: flexandmargin-topjumbled in the same selector → no distinction (Intentional dual-role cases are a different matter)
Writing margin with intent vs. gut feeling fundamentally changes how fragile your code is. Once you internalize this foundation and revisit your past code, you'll likely notice you were "matching the visual result without understanding the structure."
From "Memorize" to "Learn Through Feedback"
"Be mindful of property responsibility" is easy to say, but maintaining team-wide quality through awareness alone is difficult. This is the same problem as naming conventions — the limits of the "memorize and follow" model.
In SpiraCSS, which I develop, this approach is built into Stylelint rules. Write margin-top on a child component, and lint prompts you to specify it from the parent side. Whether a human writes it or AI generates it, you get the same feedback.
I've written in more detail about this shift from "memorize rules" to "converge through feedback" in a separate series:
Naming organizes appearance. Responsibility organizes structure.
Next time you write CSS, check just one thing — "Is this property the parent's responsibility, or the child's?" That alone changes how your code breaks.
Top comments (0)