At the end of 2020, I wrote about how CSS Logical Properties Are the Future of the Web & I18N. Since then, I've used and advocated for the new properties heavily as I see them as the next huge step toward creating truly fluid and inclusive UIs.
However, browser support requirements for the products I was working on didn't always align with browser support for logical properties. So I started writing and re-using various mixins to allow the gradual use of logical CSS through progressive enhancement with physical box model fallbacks when needed.
I'd first written the mixins for Styled Components. Later, I needed to convert those same mixins into a SCSS project. And it was here that Rhubarb CSS was born.
Rhubarb CSS
🚀 View Rhubarb CSS on GitHub
Rhubarb CSS is a collection of mixins to support writing progressively-enhanced logical CSS in many different flavors.
What started as a collection of mixins for just Styled Components, is now a collection of mixins for SCSS, Stylus and Less.
Rhubarb Styled Components
So what exactly do these mixins do?
import { Margin, Padding } from "@rhubarb-css/styled-components";
const Container = styled.section`
${Margin({ inline: "auto" })};
${Padding({ block: "var(--custom-property-value)" })};
`;
This example, would generate the following CSS.
section {
margin-inline-end: auto;
margin-inline-block: auto;
padding-block-end: var(--custom-property-value);
padding-block-start: var(--custom-property-value);
@supports not (margin-inline-end: 1rem) {
margin-left: auto;
margin-right: auto;
}
@supports not (padding-block-end: 1rem) {
padding-bottom: var(--custom-property-value);
padding-top: var(--custom-property-value);
}
}
An added benefit when using Rhubarb Styled Components is the TypeScript autocompletion of properties and values.
With the compiled CSS, the logical properties are prioritized. In environments where they're not supported, the @supports
query will be triggered, and the physical-property equivalents are used as fallbacks. Eventually, as browser support catches up and becomes broad enough, the @supports
query will no longer be needed.
Rhubarb CSS Scope
There were a couple key goals when creating the Rhubarb CSS library:
- Keep APIs consistent across projects
- Support all logical properties with direct physical fallbacks
Mixin APIs
Because of the support for Styled Components, the API conventions were generally pegged to this environment, as the outlier.
All property keys follow a camelCase naming convention, with any processor-specific leading character, such as $
for SCSS and @
for Less.
// Styled Components
blockSize
// SCSS
$blockSize
// Less
@blockSize
// Stylus
blockSize
Logical Property Support (v0.2.0)
Here is a list of logical property support and their fallback properties.
Border
Prop | CSS Property (Fallback) |
---|---|
border | border |
borderColor | border-color |
borderStyle | border-style |
borderWidth | border-width |
block | border-block-start/end (border-top/bottom) |
blockColor | border-block-start/end-color (border-top/bottom-color) |
blockStyle | border-block-start/end-style (border-top/bottom-style) |
blockWidth | border-block-start/end-width (border-top/bottom-width) |
blockEnd | border-block-end (border-bottom) |
blockEndColor | border-block-end-color (border-bottom-color) |
blockEndStyle | border-block-end-style (border-bottom-style) |
blockEndWidth | border-block-end-width (border-bottom-width) |
blockStart | border-block-start (border-top) |
blockStartColor | border-block-start-color (border-top-color) |
blockStartStyle | border-block-start-style (border-top-style) |
blockStartWidth | border-block-start-width (border-top-width) |
inline | border-inline-start/end (border-left/right) |
inlineColor | border-inline-start/end-color (border-left/right-color) |
inlineStyle | border-inline-start/end-style (border-left/right-style) |
inlineWidth | border-inline-start/end-width (border-left/right-width) |
inlineEnd | border-inline-end (border-right) |
inlineEndColor | border-inline-end-color (border-right-color) |
inlineEndStyle | border-inline-end-style (border-right-style) |
inlineEndWidth | border-inline-end-width (border-right-width) |
inlineStart | border-inline-start (border-left) |
inlineStartColor | border-inline-start-color (border-left-color) |
inlineStartStyle | border-inline-start-style (border-left-style) |
inlineStartWidth | border-inline-start-width (border-left-width) |
Border Radius
Prop | CSS Property (Fallback) |
---|---|
bottomLeft | border-end-start-radius (border-bottom-left-radius) |
bottomRight | border-end-end-radius (border-bottom-right-radius) |
radius | border-radius |
topLeft | border-start-start-radius (border-top-left-radius) |
topRight | border-start-end-radius (border-top-right-radius) |
Layout
Prop | CSS Property (Fallback) |
---|---|
blockSize | block-size (height) |
maxBlockSize | max-block-size (max-height) |
minBlockSize | min-block-size (min-height) |
inlineSize | inline-size (width) |
maxInlineSize | max-inline-size (max-width) |
minInlineSize | min-inline-size (min-width) |
overflow | overflow |
overflowBlock | overflow-block (overflow-x) |
overflowInline | overflow-inline (overflow-y) |
overscrollBehavior | overscroll-behavior |
overscrollBehaviorBlock | overscroll-behavior-block (overscroll-behavior-x) |
overscrollBehaviorInline | overscroll-behavior-inline (overscroll-behavior-y) |
resize | resize |
textAlign | text-align |
Margin
Prop | CSS Property (Fallback) |
---|---|
block | margin-block-start/end (margin-bottom/top) |
blockEnd | margin-block-end (margin-bottom) |
blockStart | margin-block-start (margin-top) |
inline | margin-inline-start/end (margin-left/right) |
inlineEnd | margin-inline-end (margin-right) |
inlineStart | margin-inline-start (margin-left) |
margin | margin |
scroll | scroll-margin |
scrollBlock | scroll-margin-block-start/end (scroll-margin-top/bottom) |
scrollBlockEnd | scroll-margin-block-end (scroll-margin-bottom) |
scrollBlockStart | scroll-margin-block-start (scroll-margin-top) |
scrollInline | scroll-margin-inline-start/end (scroll-margin-left/right) |
scrollInlineEnd | scroll-margin-inline-end (scroll-margin-right) |
scrollInlineStart | scroll-margin-inline-start (scroll-margin-left) |
Padding
Prop | CSS Property (Fallback) |
---|---|
block | padding-block-start/end (_padding-top/bottom) |
blockEnd | padding-block-end (padding-bottom) |
blockStart | padding-block-start (padding-top) |
inline | padding-inline-start/end (padding-left/right) |
inlineEnd | padding-inline-end (padding-right) |
inlineStart | padding-inline-start (padding-left) |
padding | padding |
scroll | scroll-padding |
scrollBlock | scroll-padding-block-start/end (scroll-padding-top/bottom) |
scrollBlockEnd | scroll-padding-block-end (scroll-padding-bottom) |
scrollBlockStart | scroll-padding-block-start (scroll-padding-top) |
scrollInline | scroll-padding-inline-start/end (scroll-padding-left/right) |
scrollInlineEnd | scroll-padding-inline-end (scroll-padding-right) |
scrollInlineStart | scroll-padding-inline-start (scroll-padding-left) |
Position
Prop | CSS Property (Fallback) |
---|---|
blockEnd | inset-block-end (bottom) |
blockStart | inset-block-start (top) |
inlineEnd | inset-inline-end (right) |
inlineStart | inset-inline-start (left) |
position | position |
z | z-index |
Wrap Up
Is there a need for this? At least for me there was. So why not? Isn't that the whole point of open source? Hopefully, someone else will find it useful in moving their project toward logical properties.
Either way, I'm quite happy with this.
Discussion (0)