首页 > web前端 > css教程 > 使用内联CSS自定义属性和calc()有效的无限实用助手

使用内联CSS自定义属性和calc()有效的无限实用助手

Christopher Nolan
发布: 2025-03-21 10:45:16
原创
310 人浏览过

Efficient Infinite Utility Helpers Using Inline CSS Custom Properties and calc()

最近我编写了一个非常基本的Sass循环,它输出多个填充和边距实用程序类。没什么特别的,只是一个包含11个间距值的Sass映射,循环用于在每一侧创建填充和边距的类。正如我们将看到的,这有效,但最终会产生相当大量的CSS。我们将对其进行重构以使用CSS自定义属性,并使系统更加简洁。

以下是原始Sass实现:

<code>$space-stops: (
  '0': 0,
  '1': 0.25rem,
  '2': 0.5rem,
  '3': 0.75rem,
  '4': 1rem,
  '5': 1.25rem,
  '6': 1.5rem,
  '7': 1.75rem,
  '8': 2rem,
  '9': 2.25rem,
  '10': 2.5rem,
);

@each $key, $val in $space-stops {
  .p-#{$key} {
    padding: #{$val} !important;
  }
  .pt-#{$key} {
    padding-top: #{$val} !important;
  }
  .pr-#{$key} {
    padding-right: #{$val} !important;
  }
  .pb-#{$key} {
    padding-bottom: #{$val} !important;
  }
  .pl-#{$key} {
    padding-left: #{$val} !important;
  }
  .px-#{$key} {
    padding-right: #{$val} !important;
    padding-left: #{$val} !important;
  }
  .py-#{$key} {
    padding-top: #{$val} !important;
    padding-bottom: #{$val} !important;
  }

  .m-#{$key} {
    margin: #{$val} !important;
  }
  .mt-#{$key} {
    margin-top: #{$val} !important;
  }
  .mr-#{$key} {
    margin-right: #{$val} !important;
  }
  .mb-#{$key} {
    margin-bottom: #{$val} !important;
  }
  .ml-#{$key} {
    margin-left: #{$val} !important;
  }
  .mx-#{$key} {
    margin-right: #{$val} !important;
    margin-left: #{$val} !important;
  }
  .my-#{$key} {
    margin-top: #{$val} !important;
    margin-bottom: #{$val} !important;
  }
}</code>
登录后复制

这段代码运行良好,输出了所有需要的实用程序类。但是,它也可能很快变得臃肿。在我的例子中,它们未压缩时约为8.6kb,压缩后不到1kb。(Brotli为542字节,gzip为925字节。)

由于它们非常重复,因此压缩效果很好,但我仍然无法摆脱所有这些类都是多余的感觉。此外,我甚至没有进行任何小型/中型/大型断点,而这些断点对于这类辅助类来说相当典型。

以下是添加小型/中型/大型类后响应式版本的一个人为示例。我们将重用前面定义的$space-stops映射,并将重复的代码放入mixin中

<code>@mixin finite-spacing-utils($bp: '') {
    @each $key, $val in $space-stops {
        .p-#{$key}#{$bp} {
            padding: #{$val} !important;
        }
        .pt-#{$key}#{$bp} {
            padding-top: #{$val} !important;
        }
        .pr-#{$key}#{$bp} {
            padding-right: #{$val} !important;
        }
        .pb-#{$key}#{$bp} {
            padding-bottom: #{$val} !important;
        }
        .pl-#{$key}#{$bp} {
            padding-left: #{$val} !important;
        }
        .px-#{$key}#{$bp} {
            padding-right: #{$val} !important;
            padding-left: #{$val} !important;
        }
        .py-#{$key}#{$bp} {
            padding-top: #{$val} !important;
            padding-bottom: #{$val} !important;
        }

        .m-#{$key}#{$bp} {
            margin: #{$val} !important;
        }
        .mt-#{$key}#{$bp} {
            margin-top: #{$val} !important;
        }
        .mr-#{$key}#{$bp} {
            margin-right: #{$val} !important;
        }
        .mb-#{$key}#{$bp} {
            margin-bottom: #{$val} !important;
        }
        .ml-#{$key}#{$bp} {
            margin-left: #{$val} !important;
        }
        .mx-#{$key}#{$bp} {
            margin-right: #{$val} !important;
            margin-left: #{$val} !important;
        }
        .my-#{$key}#{$bp} {
            margin-top: #{$val} !important;
            margin-bottom: #{$val} !important;
        }
    }
}

@include finite-spacing-utils;

@media (min-width: 544px) {
    @include finite-spacing-utils($bp: '_sm');
}

@media (min-width: 768px) {
    @include finite-spacing-utils($bp: '_md');
}

@media (min-width: 1024px) {
    @include finite-spacing-utils($bp: '_lg');
}
</code>
登录后复制

未压缩时约为41.7kb(Brotli约为1kb,gzip约为3kb)。它仍然压缩得很好,但这有点荒谬。

我知道可以使用[attr()函数从CSS中引用data-*属性,因此我想知道是否可以将calc()attr()一起使用,通过data-*属性(例如data-m="1"data-m="1@md")创建动态计算的间距实用程序辅助程序,然后在CSS中执行类似margin: calc(attr(data-m) * 0.25rem)的操作(假设我使用以0.25rem为增量的间距比例)。这可能非常强大。

但故事的结局是:你(目前)不能将attr()与除content属性之外的任何属性一起使用。太糟糕了。但在搜索attr()calc()信息时,我发现了Simon Rigét在Stack Overflow上发表的这篇有趣的评论,它建议直接在内联样式属性中设置CSS变量。啊哈!

因此,可以执行以下操作:<div style="--p: 4;">,然后在CSS中: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">&lt;code&gt;:root { --p: 0; } [style*='--p:'] { padding: calc(0.25rem * var(--p)) !important; }&lt;/code&gt;</pre><div class="contentsignin">登录后复制</div></div> <p>在<code>style="--p: 4;"示例中,你将有效地得到padding: 1rem !important;

……现在你有一个无限可扩展的间距实用程序类怪物助手。

以下是CSS中可能的样子:

<code>:root {
  --p: 0;
  --pt: 0;
  --pr: 0;
  --pb: 0;
  --pl: 0;
  --px: 0;
  --py: 0;
  --m: 0;
  --mt: 0;
  --mr: 0;
  --mb: 0;
  --ml: 0;
  --mx: 0;
  --my: 0;
}

[style*='--p:'] {
  padding: calc(0.25rem * var(--p)) !important;
}
[style*='--pt:'] {
  padding-top: calc(0.25rem * var(--pt)) !important;
}
[style*='--pr:'] {
  padding-right: calc(0.25rem * var(--pr)) !important;
}
[style*='--pb:'] {
  padding-bottom: calc(0.25rem * var(--pb)) !important;
}
[style*='--pl:'] {
  padding-left: calc(0.25rem * var(--pl)) !important;
}
[style*='--px:'] {
  padding-right: calc(0.25rem * var(--px)) !important;
  padding-left: calc(0.25rem * var(--px)) !important;
}
[style*='--py:'] {
  padding-top: calc(0.25rem * var(--py)) !important;
  padding-bottom: calc(0.25rem * var(--py)) !important;
}

[style*='--m:'] {
  margin: calc(0.25rem * var(--m)) !important;
}
[style*='--mt:'] {
  margin-top: calc(0.25rem * var(--mt)) !important;
}
[style*='--mr:'] {
  margin-right: calc(0.25rem * var(--mr)) !important;
}
[style*='--mb:'] {
  margin-bottom: calc(0.25rem * var(--mb)) !important;
}
[style*='--ml:'] {
  margin-left: calc(0.25rem * var(--ml)) !important;
}
[style*='--mx:'] {
  margin-right: calc(0.25rem * var(--mx)) !important;
  margin-left: calc(0.25rem * var(--mx)) !important;
}
[style*='--my:'] {
  margin-top: calc(0.25rem * var(--my)) !important;
  margin-bottom: calc(0.25rem * var(--my)) !important;
}
</code>
登录后复制

这与上面的第一个Sass循环非常相似,但没有11次循环——但它是无限的。它大约是1.4kb未压缩,Brotli为226字节,gzip为284字节。

如果你想将其扩展到断点,不幸的消息是,你不能将“@”字符放在CSS变量名中(尽管奇怪的是允许使用表情符号和其他UTF-8字符)。因此,你可能可以设置像p_sm或sm_p这样的变量名。你必须添加一些额外的CSS变量和一些媒体查询来处理所有这些,但它不会像使用Sass for循环创建的传统CSS类名那样呈指数级增长。

以下是等效的响应式版本。我们将再次使用Sass mixin来减少重复:

<code>:root {
  --p: 0;
  --pt: 0;
  --pr: 0;
  --pb: 0;
  --pl: 0;
  --px: 0;
  --py: 0;
  --m: 0;
  --mt: 0;
  --mr: 0;
  --mb: 0;
  --ml: 0;
  --mx: 0;
  --my: 0;
}

@mixin infinite-spacing-utils($bp: '') {
    [style*='--p#{$bp}:'] {
        padding: calc(0.25rem * var(--p#{$bp})) !important;
    }
    [style*='--pt#{$bp}:'] {
        padding-top: calc(0.25rem * var(--pt#{$bp})) !important;
    }
    [style*='--pr#{$bp}:'] {
        padding-right: calc(0.25rem * var(--pr#{$bp})) !important;
    }
    [style*='--pb#{$bp}:'] {
        padding-bottom: calc(0.25rem * var(--pb#{$bp})) !important;
    }
    [style*='--pl#{$bp}:'] {
        padding-left: calc(0.25rem * var(--pl#{$bp})) !important;
    }
    [style*='--px#{$bp}:'] {
        padding-right: calc(0.25rem * var(--px#{$bp})) !important;
        padding-left: calc(0.25rem * var(--px)#{$bp}) !important;
    }
    [style*='--py#{$bp}:'] {
        padding-top: calc(0.25rem * var(--py#{$bp})) !important;
        padding-bottom: calc(0.25rem * var(--py#{$bp})) !important;
    }
    [style*='--m#{$bp}:'] {
        margin: calc(0.25rem * var(--m#{$bp})) !important;
    }
    [style*='--mt#{$bp}:'] {
        margin-top: calc(0.25rem * var(--mt#{$bp})) !important;
    }
    [style*='--mr#{$bp}:'] {
        margin-right: calc(0.25rem * var(--mr#{$bp})) !important;
    }
    [style*='--mb#{$bp}:'] {
        margin-bottom: calc(0.25rem * var(--mb#{$bp})) !important;
    }
    [style*='--ml#{$bp}:'] {
        margin-left: calc(0.25rem * var(--ml#{$bp})) !important;
    }
    [style*='--mx#{$bp}:'] {
        margin-right: calc(0.25rem * var(--mx#{$bp})) !important;
        margin-left: calc(0.25rem * var(--mx#{$bp})) !important;
    }
    [style*='--my#{$bp}:'] {
        margin-top: calc(0.25rem * var(--my#{$bp})) !important;
        margin-bottom: calc(0.25rem * var(--my#{$bp})) !important;
    }
}

@include infinite-spacing-utils;

@media (min-width: 544px) {
    @include infinite-spacing-utils($bp: '_sm');
}

@media (min-width: 768px) {
    @include infinite-spacing-utils($bp: '_md');
}

@media (min-width: 1024px) {
    @include infinite-spacing-utils($bp: '_lg');
}
</code>
登录后复制

大约6.1kb未压缩,Brotli为428字节,gzip为563字节。

我认为编写像<div style="--px:2; --my:4;">这样的HTML是否赏心悦目,或者良好的开发者人体工程学……不,不是特别。但这种方法在某些情况下是否可行,例如你(由于某种原因)需要极少的CSS,或者根本不需要外部CSS文件?是的,我当然认为可以。值得在此指出的是,在内联样式中分配的CSS变量不会泄漏。它们仅作用于当前元素,不会改变全局变量的值。谢天谢地!到目前为止,我发现的一个奇怪之处是,DevTools(至少在Chrome、Firefox和Safari中)不会在“计算”样式选项卡中报告使用此技术的样式。 <p>还值得一提的是,我已经使用了传统的padding和margin属性以及-top、-right、-bottom和-left,但是你可以使用等效的逻辑属性,如padding-block和padding-inline。通过选择性地混合和匹配逻辑属性和传统属性,甚至可以减少几字节。通过这种方式,我设法将Brotli压缩到400字节,gzip压缩到521字节。</p> <h3>其他用例</h3> <p>这似乎最适合线性增量比例的事物(这就是为什么padding和margin似乎是一个很好的用例),但我可以看到这可能适用于网格系统中的宽度和高度(列数和/或宽度)。<strong>也许</strong>适用于排版比例(但也许不适用)。</p> <p>我非常关注文件大小,但这里可能还有一些我没有想到的其他用途。也许<strong>你</strong>不会以这种方式编写代码,但关键CSS工具可能会重构代码以使用这种方法。</p> <h3>深入挖掘</h3> <p>当我深入研究时,我发现Ahmad Shadeed在2019年的一篇博客文章中讨论了将<code>calc()与内联样式中的CSS变量赋值混合使用,特别是对于头像大小。Miriam Suzanne在2019年发表在Smashing Magazine上的文章没有使用calc(),但分享了一些使用内联样式中的变量赋值可以实现的惊人功能。

以上是使用内联CSS自定义属性和calc()有效的无限实用助手的详细内容。更多信息请关注PHP中文网其他相关文章!

上一篇:CSS模块(本地模块) 下一篇:可能无法正常工作的网络功能
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
相关专题
更多>
热门推荐
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板