I think creating responsive CSS using current technology is very inconvenient.
(我认为使用当前技术创建响应式CSS非常不便。)
I came up with the idea of ??a CSS preprocessor with entities (they are called "Features") and states for these entities.(我想到了一个带有实体的CSS预处理器(它们称为``功能'')和这些实体的状态的想法。)
I called this CSS preprocessor "Features CSS."(我将此CSS预处理器称为“功能CSS”。)
See how convenient it is to create responsive CSS using "Features CSS":(看看使用“功能CSS”创建响应式CSS有多么方便:)
"Features CSS" description(“功能CSS”说明)
For example, we need to create a toggleable sidebar.
(例如,我们需要创建一个可切换的侧边栏。)
See how “Features CSS” allows you to conveniently create the CSS:(请参阅“功能CSS”如何方便地创建CSS:)
//=======================================
// $app-feature: This is global app feature
//=======================================
$app-feature: @feature(
parent: null,
states: (
//
// This window width states can be used as app global responsive breakpoints (as in Bootstrap).
// You can also add other parallel group of window width states.
// You can also add other parallel group of window width states from any other feature and
// register this group of states in this feature.
// States in any feature can be published in any other feature.
// You can access feature states from any other feature.
//
extra-small: 500px, // window width in range [0; 500px]
small: 767px, // window width in range [501px, 767px]
medium: 1024px, // window width in range [768px, 1024px]
large: 1200px, // window width in range [1025px, 1200px]
// Last element must be null (i.e. max-width is infinity)
extra-large: null, // window width in range [1201px, Infinity)
),
// "states" this is shortcut for "states-ex.win-width".
// "states-ex.win-width" this is states based on window width.
// Instead of "states" you can write:
// states-ex: {
// win-width: (
// ...
// ),
// }
);
//=======================================
// $side-menu-feature: This is side menu feature
//=======================================
$side-menu-feature: @feature(
parent: $app-feature,
states-ex: (
//
// "win-width" is system states group based on window width
//
win-width: (
toggleable: $app-feature{medium} ( // i.e. {extra-small}, {small} and {medium}
vars: (
side-width: 80%,
),
),
fixed-small: $app-feature{large} ( // i.e. {large}
vars: (
side-width: 300px,
),
),
// Last breakpoint must be null (i.e. max-width is infinity)
// You can write also:
// fixed-large: $app-feature{extra-large}
// because $app-feature{extra-large} also is last breakpoint and therefore it also equals to null
fixed-large: null ( // i.e. {extra-large}
vars: (
side-width: 400px,
),
),
),
//
// Create custom state group #opening
// Name of custom states group must starts with #
//
#opening: @selector-state( // States
opened: body.side-menu--opened,
closed: body:not(.side-menu--opened),
) ( // Options
// Publish this state in $app-feature
publish: $app-feature{#side-menu-opening},
// And now you can access this state from $app-feature in your any CSS file:
// @state $app-feature{#side-menu-opening.opened} {
// .my-item {
// font-weight: bold;
// }
// }
),
),
) {
.side-menu {
background-color: #fff;
}
.side-menu-overlay {
position: relative;
opacity: 0.5;
color: #444;
}
// Same as: @state win-width.toggleable
@state .toggleable {
@state #opening.opened {
.side-menu {
width: @var [side-width];
// Same as: @var win-width[side-width]
// It takes "width" variable from current win-width state (win-width.toggleable)
// You can take variable from other current state: @var #opening[my-var]
// Or from other not current but explicit state: @var #opening.closed[my-var]
}
.side-menu-overlay {
z-index: 100;
}
.main-content {
margin-left: @var [side-width];
width: 100%;
}
}
@state #opening.closed {
.side-menu,
.side-menu-overlay {
display: none;
}
.side-menu-overlay {
z-index: -100;
}
}
}
// Same as: @state @up win-width.small
// Same as: @state win-width(fixed-small, fixed-large)
// Same as: @state .(fixed-small, fixed-large)
@state @up .fixed-small {
.side-menu {
position: fixed;
left: 0;
width: @var [side-width]; // side-width equals to 300px for fixed-small and 400px for fixed-large
top: 0;
bottom: 0;
}
.main-content {
margin-left: @var [side-width];
width: calc(100% - @var [side-width]);
}
}
}
//=======================================
// $side-menu-item-feature
//=======================================
$side-menu-item-feature: @feature(
parent: $side-menu-feature,
states: (
toggleable: @parent{toggleable} => item-large,
fixed-small: @parent{fixed-small} => item-small,
fixed-large: @parent{fixed-large} => item-large,
// You can use readble state names "item-small" or "item-large" instead of unreadble
// global app states $app-feature{extra-small}, $app-feature{small}.
// $app-feature{...} states unreadble in context of side-menu-item
// because $app-feature{...} states based on the browser width
// and therefore $app-feature{...} state names semantic based on browser width
// and therefore $app-feature{...} state names is unreadble in context of side-menu-item
//
// or
//
// If toggleable side-menu has width in percentage of screen
// and therefore side-menu width is proportional to the browser window width
// then we can do the following:
toggleable-small: @parent{{toggleable, 720px}} => item-small,
// @parent{{toggleable, 720px}} takes 720px and ensures
// that 720px is in "toggleable" window width range.
// Otherwise compilation error occured.
toggleable-large: @parent{toggleable} => item-large,
// or:
// toggleable-small: @parent{{toggleable, 70%}} => item-small,
// toggleable-large: @parent{toggleable} => item-large,
//
// @parent{toggleable} (@side-menu-feature{toggleable}) has such rule:
// browser-width in range [0px, 1024px]
//
// Since the width of the side-menu is proportional to the width of the browser window,
// we know that for small browser widths the menu is narrow (therefore menu item is small),
// and for large browser widths the menu is wide (therefore menu item is large).
//
// But also we can implement "side-menu-item" state depends not from browser width value,
// but depends from "side-menu-item" element width value using "Features CSS JS Ext"
//
fixed-small: @parent{fixed-small} => item-small,
fixed-large: @parent{fixed-large} => item-large,
),
) {
// This causes compilation error.
// Use {item-small} or {item-large} states.
@state .toggleable {}
// This is works
@state .item-small {
}
@state .item-large {
}
}
//=======================================
// $side-menu-item-sub-element-feature
//=======================================
$side-menu-item-sub-element-feature: @feature(
parent: $side-menu-item-feature,
states: @parent.states,
) {
@state .item-small {
...
}
@state .item-large {
...
}
}
Additional examples for "Features CSS"(“功能CSS”的其他示例)
//=======================================
// Applying of feature
//=======================================
$my-feature: @feature(
parent: null,
states: (
small: 1024px,
large: null,
),
) {
// Same as: @state @up win-width.small
@state @up .small {
.test-class { font-weight: bold; }
}
}
// You can also apply feature in any your CSS file
@apply $my-feature {
@state @up .small {
.test-class { font-weight: bold; }
}
}
// Or use $my-feature states explicitly
// Same as: @state @up $my-feature{win-width.small} {
@state @up $my-feature{.small} {
.test-class { font-weight: bold; }
}
//=======================================
// Parallel states example
//=======================================
$my-feature: @feature(
parent: null,
states-ex: (
win-width: (
small: 1024px,
large: null,
),
//
// Custom state based on window width
//
#right-bar: @win-width-state(
hide-right-bar: 1200px,
show-right-bar: null,
)
// Both "win-width" and "#right-bar" states based on window width.