What about this case:
- when .parent is small we want to stack our children
- when .parent is larger let the children use their auto size
<div class="parent">
<button class="child">button</button>
<button class="child">button</button>
</div>
.parent {
display: flex;
background: orange;
flex-direction: column;
}
@media (min-width: 500px) {
.parent {
flex-direction: initial;
}
}
.child {
display: block;
}
Instead of having the children define their size with a condition we can define the condition on the parent and use flexbox to decide how they are going to be layout out. css grid does calculation on its container size and decide how to layout their children depending their size (auto-fit, minmax).
I think this solution does not suffer the cyclical problem:
.parent {
display: flex;
background: orange;
flex-direction: if(min-width: 200px, initial, column) ;
// equivalent in javascript
// let flexDirection = width <= 200px ? 'initial' : 'column';
}
.child {
display: block;
}
we could use it to create simple condition with css vars too
.parent {
--state: true;
}
.child {
color: if(var(--state), red, blue);
}
A more powerful approach would be to use if() with css grid, usually you would use media query
.grid {
display: grid;
grid-gap: 10px 20px;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr 1fr auto;
grid-template-areas:
'header'
'none'
'none'
'button'
;
margin-top: 10px;
padding: 10px;
border: 1px solid gray;
border-radius: 4px;
}
@media (min-width: 500px) {
.grid {
grid-template-columns: 1fr 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
'header header'
'none none'
'button button'
;
}
}
.grid h1 {
text-align: center;
grid-area: header;
}
.grid label {
display: flex;
align-items: center;
}
.grid input {
flex-grow: 1;
margin-right: 10px;
}
.grid button {
background-color: #03a9f4;
grid-column-start: 1;
grid-column-end: span 2;
grid-area: button;
}
with if() and other possible operators
/* option 1 */
.grid {
display: grid;
grid-gap: 10px 20px;
grid-template-columns: if(min-width: 300px,
1fr 1fr,
1fr
);
grid-template-rows: if(min-width: 300px,
auto 1fr 1fr auto,
auto 1fr auto
);
grid-template-areas: if(min-width: 300px,
'header header'
'none none'
'button button',
'header'
'none'
'none'
'button'
);
}
/* option 2 */
.grid {
display: grid;
grid-gap: 10px 20px;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
'header'
'none'
'none'
'button'
;
@when (min-width: 300px) {
grid-template-columns: 1fr 1fr;
grid-template-rows: auto 1fr 1fr auto;
grid-template-areas:
'header header'
'none none'
'button button'
;
}
}
/* option 3 */
.grid {
grid-template-columns: 1fr;
...
@minwidth (300px) {
grid-template-columns: 1fr 1fr;
...
}
}
/* option 4 */
.grid {
grid-template-columns: minwidth(300px, 1fr 1fr, 1fr);
grid-template-columns: maxwidth(300px, 1fr, 1fr 1fr);
}
Syntax wise I think we could think something more concise but I think what we are doing here is not far from css grid fit-content minmax
All examples are on jsfiddle: https://jsfiddle.net/b6gmo8mn/4/