最近我編寫了一個非常基本的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中文網其他相關文章!