Less CSS - 减少重复
Less CSS - cut down repetition
我在 Less 中有以下代码:
我很确定这可以通过某种混音进一步抽象出来,但我已经摸索了一段时间了。我希望能够传入一个变量,例如@xs 或@xs-gutter,并让函数填充代码。
有什么想法吗?
.padding
{
&.bottom {
padding-bottom: @xs-gutter;
}
&.left {
padding-left: @xs-gutter;
}
&.right {
padding-right: @xs-gutter;
}
&.top {
padding-top: @xs-gutter;
}
@media @sm-screen {
&.bottom {
padding-bottom: @sm-gutter;
}
&.left {
padding-left: @sm-gutter;
}
&.right {
padding-right: @sm-gutter;
}
&.top {
padding-top: @sm-gutter;
}
}
@media @md-screen {
&.bottom {
padding-bottom: @md-gutter;
}
&.left {
padding-left: @md-gutter;
}
&.right {
padding-right: @md-gutter;
}
&.top {
padding-top: @md-gutter;
}
}
@media @lg-screen {
&.bottom {
padding-bottom: @lg-gutter;
}
&.left {
padding-left: @lg-gutter;
}
&.right {
padding-right: @lg-gutter;
}
&.top {
padding-top: @lg-gutter;
}
}
}
您可以使用循环和数组列表来减少代码中的重复。以下是关于如何实现 reduction.Refer 内联注释的示例片段,用于解释代码的作用。
Note: I have made the actual padding generation mixin as a separate one which takes the sides as an argument because you can re-use that mixin to generate padding for multiple sides (by passing the sides and gutter as arguments) without generating media-queries for them.
@gutters: 4px, 6px, 8px, 10px; // the gutter sizes corresponding to each screen size
@media-sizes: xs, sm, lg, md; // possible screen sizes
@media-conditions: ~"(min-width: 100px)", ~"(min-width: 150px)", ~"(min-width: 200px)", ~"(min-width: 250px)"; // media condition for each screen size
.media-generator(){
.loop-sizes(length(@media-sizes)); // loop through all screen sizes
.loop-sizes(@screenIndex) when (@screenIndex > 0) {
& when (extract(@media-sizes, @screenIndex) = xs){ // since we need xs as default
.padding-per-side(extract(@gutters, 1); left; right; bottom; top);
}
& when not (extract(@media-sizes, @screenIndex) = xs){ // when screen size is not xs
@condition: extract(@media-conditions, @screenIndex); // extract media condition corresponding to screen type
@media @condition{
.padding-per-side(extract(@gutters, @screenIndex); left; right; bottom; top); // call the mixin to generate padding for all sides
}
}
.loop-sizes(@screenIndex - 1);
}
}
.padding-per-side(@gutter; @sides...){
.loop-sides(length(@sides));
.loop-sides(@index) when (@index > 0){
@side: extract(@sides, @index);
&.@{side}{
padding-@{side}: @gutter;
}
.loop-sides(@index - 1);
}
}
.padding{
.media-generator(); // generate padding for all sides and screens like in question
}
#demo{ // extra :)
.padding-per-side(10px; left;right); // generates 10px padding for left and right
}
下面是上面的增强版本,它允许我们只为某些方面生成带有媒体查询的填充。下面的代码片段和上面的代码片段之间的区别在于,在这里您可以单独为特定的边生成填充以及它们的媒体查询版本。
@gutters: 4px, 6px, 8px, 10px;
@media-sizes: xs, sm, lg, md;
@media-conditions: ~"(min-width: 100px)", ~"(min-width: 150px)", ~"(min-width: 200px)", ~"(min-width: 250px)";
.media-generator(@sides...){
& when (length(@sides) = 0){
.loop-sizes(length(@media-sizes));
.loop-sizes(@screenIndex) when (@screenIndex > 0) {
& when (extract(@media-sizes, @screenIndex) = xs){
.padding-per-side(extract(@gutters, 1); left; right; bottom; top);
}
& when not (extract(@media-sizes, @screenIndex) = xs){
@condition: extract(@media-conditions, @screenIndex);
@media @condition{
.padding-per-side(extract(@gutters, @screenIndex); left; right; bottom; top);
}
}
.loop-sizes(@screenIndex - 1);
}
}
& when not (length(@sides) = 0){
.loop-sizes(length(@media-sizes));
.loop-sizes(@screenIndex) when (@screenIndex > 0) {
& when (extract(@media-sizes, @screenIndex) = xs){
.padding-per-side(extract(@gutters, 1); @sides);
}
& when not (extract(@media-sizes, @screenIndex) = xs){
@condition: extract(@media-conditions, @screenIndex);
@media @condition{
.padding-per-side(extract(@gutters, @screenIndex); @sides);
}
}
.loop-sizes(@screenIndex - 1);
}
}
}
.padding-per-side(@gutter; @sides...){
.loop-sides(length(@sides));
.loop-sides(@index) when (@index > 0){
@side: extract(@sides, @index);
&.@{side}{
padding-@{side}: @gutter;
}
.loop-sides(@index - 1);
}
}
.padding{
.media-generator(left; right); // specify sides if needed else leave blank
}
我个人细化了3种可能的方案,从最简单的开始,然后优化到第3种。最简单的具有更好的可读性,最难的使用双重嵌套 LOOP.
在这里,我报告了 3 个解决方案之间的 "common" 代码(为了更直观,我决定保留单独的可能大小定义):
@sm-screen:~"(min-width: 320px)";
@md-screen:~"(min-width: 720px)";
@lg-screen:~"(min-width: 1200px)";
@xs-gutter:20px;
@sm-gutter:30px;
@md-gutter:40px;
@lg-gutter:50px;
@property:padding;
//@property:margin;
请注意,@property
可以是“margin
”或“padding
”,只是切换注释而已。
对于这个变量定义,您可以附加以下 3 个建议:
解决方案 1
这是最简单的解决方案。缺点是它会为每个规则生成不同的mediaquery,导致代码冗余:
.side(top, right, bottom, left);
.side(@possible-values...)
{
.generate-property-loop(1, @possible-values);
}
.generate-property-loop(@var; @possible-values) when (@var <= length(@possible-values))
{
//Let's extract values in @var position from list @possible-values
@direction: extract(@possible-values, @var);
.@{property}.@{direction}
{
@{property}-@{direction}: @xs-gutter;
@media @sm-screen
{
@{property}-@{direction}: @sm-gutter;
}
@media @md-screen
{
@{property}-@{direction}: @md-gutter;
}
@media @lg-screen
{
@{property}-@{direction}: @lg-gutter;
}
}
.generate-property-loop((@var + 1), @possible-values);
}
解决方案 2
一个可能的解决方案是将媒体查询移到 LOOP 之外,但它仍然需要明确的媒体查询定义:
.side(top, right, bottom, left);
.side(@possible-values...)
{
.generate-property-loop(1, @possible-values, @xs-gutter);
@media @sm-screen
{
.generate-property-loop(1, @possible-values, @sm-gutter);
}
@media @md-screen
{
.generate-property-loop(1, @possible-values, @md-gutter);
}
@media @lg-screen
{
.generate-property-loop(1, @possible-values, @lg-gutter);
}
}
.generate-property-loop(@var, @possible-values, @gutter) when (@var <= length(@possible-values))
{
//Let's extract values in @var position from list @possible-values
@direction: extract(@possible-values, @var);
.@{property}
{
&.@{direction}
{
@{property}-@{direction}: @gutter;
}
}
.generate-property-loop((@var + 1), @possible-values, @gutter);
}
解决方案 3
使用双嵌套循环,您可以获得完全的灵活性,只需将 "directions" 和 "scren-size" 作为参数传递,但代价是可读性较小:
.side(top, right, bottom, left);
.side(@possible-values...)
{
.generate-property-loop(1, @possible-values, @xs-gutter);
.mediaquery-loop(sm,md,lg);
}
.mediaquery-loop(@possible-screens...)
{
.generate-mediaquery-loop(1, @possible-screens);
}
.generate-property-loop(@var, @possible-values, @gutter) when (@var <= length(@possible-values))
{
@direction: extract(@possible-values, @var);
.@{property}
{
&.@{direction}
{
@{property}-@{direction}: @gutter;
}
}
.generate-property-loop((@var + 1), @possible-values, @gutter);
}
.generate-mediaquery-loop(@var, @possible-sizes) when (@var <= length(@possible-screens))
{
@sizes: extract(@possible-sizes, @var);
@screen-size: ~"@{sizes}-screen";
@gutter-size: ~"@{sizes}-gutter";
@media @@screen-size
{
.generate-property-loop(1, @possible-values, @@gutter-size);
}
.generate-mediaquery-loop((@var + 1), @possible-screens);
}
我在 Less 中有以下代码:
我很确定这可以通过某种混音进一步抽象出来,但我已经摸索了一段时间了。我希望能够传入一个变量,例如@xs 或@xs-gutter,并让函数填充代码。
有什么想法吗?
.padding
{
&.bottom {
padding-bottom: @xs-gutter;
}
&.left {
padding-left: @xs-gutter;
}
&.right {
padding-right: @xs-gutter;
}
&.top {
padding-top: @xs-gutter;
}
@media @sm-screen {
&.bottom {
padding-bottom: @sm-gutter;
}
&.left {
padding-left: @sm-gutter;
}
&.right {
padding-right: @sm-gutter;
}
&.top {
padding-top: @sm-gutter;
}
}
@media @md-screen {
&.bottom {
padding-bottom: @md-gutter;
}
&.left {
padding-left: @md-gutter;
}
&.right {
padding-right: @md-gutter;
}
&.top {
padding-top: @md-gutter;
}
}
@media @lg-screen {
&.bottom {
padding-bottom: @lg-gutter;
}
&.left {
padding-left: @lg-gutter;
}
&.right {
padding-right: @lg-gutter;
}
&.top {
padding-top: @lg-gutter;
}
}
}
您可以使用循环和数组列表来减少代码中的重复。以下是关于如何实现 reduction.Refer 内联注释的示例片段,用于解释代码的作用。
Note: I have made the actual padding generation mixin as a separate one which takes the sides as an argument because you can re-use that mixin to generate padding for multiple sides (by passing the sides and gutter as arguments) without generating media-queries for them.
@gutters: 4px, 6px, 8px, 10px; // the gutter sizes corresponding to each screen size
@media-sizes: xs, sm, lg, md; // possible screen sizes
@media-conditions: ~"(min-width: 100px)", ~"(min-width: 150px)", ~"(min-width: 200px)", ~"(min-width: 250px)"; // media condition for each screen size
.media-generator(){
.loop-sizes(length(@media-sizes)); // loop through all screen sizes
.loop-sizes(@screenIndex) when (@screenIndex > 0) {
& when (extract(@media-sizes, @screenIndex) = xs){ // since we need xs as default
.padding-per-side(extract(@gutters, 1); left; right; bottom; top);
}
& when not (extract(@media-sizes, @screenIndex) = xs){ // when screen size is not xs
@condition: extract(@media-conditions, @screenIndex); // extract media condition corresponding to screen type
@media @condition{
.padding-per-side(extract(@gutters, @screenIndex); left; right; bottom; top); // call the mixin to generate padding for all sides
}
}
.loop-sizes(@screenIndex - 1);
}
}
.padding-per-side(@gutter; @sides...){
.loop-sides(length(@sides));
.loop-sides(@index) when (@index > 0){
@side: extract(@sides, @index);
&.@{side}{
padding-@{side}: @gutter;
}
.loop-sides(@index - 1);
}
}
.padding{
.media-generator(); // generate padding for all sides and screens like in question
}
#demo{ // extra :)
.padding-per-side(10px; left;right); // generates 10px padding for left and right
}
下面是上面的增强版本,它允许我们只为某些方面生成带有媒体查询的填充。下面的代码片段和上面的代码片段之间的区别在于,在这里您可以单独为特定的边生成填充以及它们的媒体查询版本。
@gutters: 4px, 6px, 8px, 10px;
@media-sizes: xs, sm, lg, md;
@media-conditions: ~"(min-width: 100px)", ~"(min-width: 150px)", ~"(min-width: 200px)", ~"(min-width: 250px)";
.media-generator(@sides...){
& when (length(@sides) = 0){
.loop-sizes(length(@media-sizes));
.loop-sizes(@screenIndex) when (@screenIndex > 0) {
& when (extract(@media-sizes, @screenIndex) = xs){
.padding-per-side(extract(@gutters, 1); left; right; bottom; top);
}
& when not (extract(@media-sizes, @screenIndex) = xs){
@condition: extract(@media-conditions, @screenIndex);
@media @condition{
.padding-per-side(extract(@gutters, @screenIndex); left; right; bottom; top);
}
}
.loop-sizes(@screenIndex - 1);
}
}
& when not (length(@sides) = 0){
.loop-sizes(length(@media-sizes));
.loop-sizes(@screenIndex) when (@screenIndex > 0) {
& when (extract(@media-sizes, @screenIndex) = xs){
.padding-per-side(extract(@gutters, 1); @sides);
}
& when not (extract(@media-sizes, @screenIndex) = xs){
@condition: extract(@media-conditions, @screenIndex);
@media @condition{
.padding-per-side(extract(@gutters, @screenIndex); @sides);
}
}
.loop-sizes(@screenIndex - 1);
}
}
}
.padding-per-side(@gutter; @sides...){
.loop-sides(length(@sides));
.loop-sides(@index) when (@index > 0){
@side: extract(@sides, @index);
&.@{side}{
padding-@{side}: @gutter;
}
.loop-sides(@index - 1);
}
}
.padding{
.media-generator(left; right); // specify sides if needed else leave blank
}
我个人细化了3种可能的方案,从最简单的开始,然后优化到第3种。最简单的具有更好的可读性,最难的使用双重嵌套 LOOP.
在这里,我报告了 3 个解决方案之间的 "common" 代码(为了更直观,我决定保留单独的可能大小定义):
@sm-screen:~"(min-width: 320px)";
@md-screen:~"(min-width: 720px)";
@lg-screen:~"(min-width: 1200px)";
@xs-gutter:20px;
@sm-gutter:30px;
@md-gutter:40px;
@lg-gutter:50px;
@property:padding;
//@property:margin;
请注意,@property
可以是“margin
”或“padding
”,只是切换注释而已。
对于这个变量定义,您可以附加以下 3 个建议:
解决方案 1
这是最简单的解决方案。缺点是它会为每个规则生成不同的mediaquery,导致代码冗余:
.side(top, right, bottom, left);
.side(@possible-values...)
{
.generate-property-loop(1, @possible-values);
}
.generate-property-loop(@var; @possible-values) when (@var <= length(@possible-values))
{
//Let's extract values in @var position from list @possible-values
@direction: extract(@possible-values, @var);
.@{property}.@{direction}
{
@{property}-@{direction}: @xs-gutter;
@media @sm-screen
{
@{property}-@{direction}: @sm-gutter;
}
@media @md-screen
{
@{property}-@{direction}: @md-gutter;
}
@media @lg-screen
{
@{property}-@{direction}: @lg-gutter;
}
}
.generate-property-loop((@var + 1), @possible-values);
}
解决方案 2
一个可能的解决方案是将媒体查询移到 LOOP 之外,但它仍然需要明确的媒体查询定义:
.side(top, right, bottom, left);
.side(@possible-values...)
{
.generate-property-loop(1, @possible-values, @xs-gutter);
@media @sm-screen
{
.generate-property-loop(1, @possible-values, @sm-gutter);
}
@media @md-screen
{
.generate-property-loop(1, @possible-values, @md-gutter);
}
@media @lg-screen
{
.generate-property-loop(1, @possible-values, @lg-gutter);
}
}
.generate-property-loop(@var, @possible-values, @gutter) when (@var <= length(@possible-values))
{
//Let's extract values in @var position from list @possible-values
@direction: extract(@possible-values, @var);
.@{property}
{
&.@{direction}
{
@{property}-@{direction}: @gutter;
}
}
.generate-property-loop((@var + 1), @possible-values, @gutter);
}
解决方案 3
使用双嵌套循环,您可以获得完全的灵活性,只需将 "directions" 和 "scren-size" 作为参数传递,但代价是可读性较小:
.side(top, right, bottom, left);
.side(@possible-values...)
{
.generate-property-loop(1, @possible-values, @xs-gutter);
.mediaquery-loop(sm,md,lg);
}
.mediaquery-loop(@possible-screens...)
{
.generate-mediaquery-loop(1, @possible-screens);
}
.generate-property-loop(@var, @possible-values, @gutter) when (@var <= length(@possible-values))
{
@direction: extract(@possible-values, @var);
.@{property}
{
&.@{direction}
{
@{property}-@{direction}: @gutter;
}
}
.generate-property-loop((@var + 1), @possible-values, @gutter);
}
.generate-mediaquery-loop(@var, @possible-sizes) when (@var <= length(@possible-screens))
{
@sizes: extract(@possible-sizes, @var);
@screen-size: ~"@{sizes}-screen";
@gutter-size: ~"@{sizes}-gutter";
@media @@screen-size
{
.generate-property-loop(1, @possible-values, @@gutter-size);
}
.generate-mediaquery-loop((@var + 1), @possible-screens);
}