最近我编写了一个非常基本的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"><code>:root {
--p: 0;
}
[style*='--p:'] {
padding: calc(0.25rem * var(--p)) !important;
}</code></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中文网其他相关文章!