本文將和各位老鐵一塊兒探索如何使用CSS變量來下降複雜佈局和交互的代碼編寫難度,並使其更易於維護。這裏即將分享兩篇該系列的文章,本篇是分享css變量的探索應用的各類用例。(ps:看懂和理解本文須要有必定的前端基礎)
css
進入文章前,咱們先看下圖,一張網站經常使用的響應式信息圖表佈局圖,固然實現的方式不少,若是我告訴您一個CSS聲明會在如下圖像中對寬屏狀況(左測)和第二個(右測)之間產生差別,用一個CSS聲明實如今寬屏幕的狀況下對奇數項和偶數項進行區分,從而來實現下面效果,你會不會以爲有點驚喜?html
或者僅僅一個CSS聲明就能區別下面的壓縮和擴展的狀況?
前端
有點意思吧,接下來,咱們就一塊兒探索CSS變量在複雜佈局和交互的一些小運用。關於CSS變量是什麼以及如何開始使用它們的文章已經不少了,因此咱們不會在這裏深刻討論。咱們將直接深刻了解CSS變量爲何對實現這些狀況和其餘狀況有用,而後咱們將進一步詳細解釋如何實現各類狀況。咱們將從頭編寫一個實際示例,一步一步地編寫,最後,您將經過使用相同技術的更多演示得到一些引人注目的東西。因此讓咱們開始吧!(ps:本文樣式都是scss編寫)《DRY Switching with CSS Variables: The Difference of One Declaration》BY ANA TUDOR ONDECEMBER 5, 2018(注:原文)git
對我而言,CSS變量的最大優勢是它們以邏輯,數學和輕鬆的方式爲事物的樣式打開了大門。看下面這個陰陽圖,實際上是使用loader元素的兩個僞元素建立兩個半部分github
旋轉☯符號,兩個半的大小逐漸增大和減少。咱們使用相同的background,border-color,transform-origin和animation-delay值兩半。這些值都取決於--i最初設置爲0兩半(僞元素)的開關變量,但隨後咱們將其更改1爲後半部分(:after僞元素),從而動態修改全部這些屬性的計算值。sass
若是沒有CSS變量,咱們將不得再也不次在:after僞元素上設置全部這些屬性(border-color、transform-origin、background、anima -delay),並可能出現一些錯誤,甚至忘記設置其中一些屬性。
bash
在陰陽加載器的特定狀況下,咱們在兩半(僞元素)之間改變的全部屬性對於開關的一個狀態變爲零值而對於另外一個狀態變爲非零值。
ide
您能夠看到如下所示的概念:
函數
.yin-yang {
&:before, &:after {
--i: 0;
/* lightness of border-color when
* --i: 0 is (1 - 0)*100% = 1*100% = 100% (white)
* --i: 1 is (1 - 1)*100% = 0*100% = 0% (black) */
border: solid $d/6 hsl(0, 0%, calc((1 - var(--i))*100%));
/* x coordinate of transform-origin when
* --i: 0 is 0*100% = 0% (left)
* --i: 1 is 1*100% = 100% (right) */
transform-origin: calc(var(--i)*100%) 50%;
/* lightness of background-color when
* --i: 0 is 0*100% = 0% (black)
* --i: 1 is 1*100% = 100% (white) */
background: hsl(0, 0%, calc(var(--i)*100%));
/* animation-delay when
* --i: 0 is 0*-$t = 0s
* --i: 1 is 1*-$t = -$t */
animation: s $t ease-in-out calc(var(--i)*#{-$t}) infinite alternate;
}
&:after { --i: 1 }
}
複製代碼
可是,若是咱們想要在開關關閉(--i: 0)時具備非零值而在開關打開時具備另外一個不一樣的非零值(--i: 1)呢?工具
saturation()
/lightness()
函數。雖然rgb()多是更爲人所知的格式,但我更傾向於hsl()由於我發現它更直觀,並且經過查看代碼,我更容易瞭解視覺效果。所以,咱們使用如下函數提取
hsl()
兩個值的等價物的三個組成部分($c0: #ccc當開關關閉$c1: #f90時和開關打開時):
$c0: #ccc;
$c1: #f90;
$h0: round(hue($c0)/1deg);
$s0: round(saturation($c0));
$l0: round(lightness($c0));
$h1: round(hue($c1)/1deg);
$s1: round(saturation($c1));
$l1: round(lightness($c1))
複製代碼
請注意,咱們已經四捨五入的結果hue(),saturation()並lightness()做爲他們可能返回大量的小數,咱們要保持咱們生成的代碼乾淨。咱們還將hue()函數的結果除以1deg,由於在這種狀況下返回值是度值,而Edge僅支持CSS hsl()函數內的無單位值。一般,在使用Sass時,咱們可使用度數值,而不只僅是hsl()函數內部hue的單位值,由於Sass將其視爲Sass hsl()函數,它被編譯爲hsl()具備無單位色調的CSS 函數。可是在這裏,咱們內部有一個動態CSS變量,所以Sass將此函數視爲CSShsl() 沒有編譯成其餘任何東西的函數,所以,若是hue有一個單元,則不會從生成的CSS中刪除它。
如今咱們有:
咱們能夠將咱們的兩個背景寫成:
在這裏,咱們記--j的互補值--i(當--i是0,--j是1,當--i是1,--j是0)。
上述公式適用於在任意兩個HSL值之間切換。可是,在這種特殊狀況下,咱們能夠簡化它,由於當開關關閉時咱們有一個純灰色(--i: 0)。
考慮到RGB模型,純灰度值具備相等的紅色,綠色和藍色值。 當考慮HSL模型時,色調是可有可無的(咱們的灰色看起來對於全部色調都是相同的),飽和度老是0%只有亮度很重要,決定了咱們的灰色是多麼亮或暗。 在這種狀況下,咱們能夠始終保持非灰色值的色調(咱們對「on」狀況所具備的色調$h1)。
因爲任何灰度值(咱們對「關閉」狀況所具備的)的飽和度 $s0始終是0%,將其乘以0或者1老是給出咱們0%。所以,考慮到var(--j)*#{$s0}咱們的公式中的術語老是如此0%,咱們能夠放棄它,咱們的飽和公式減小到「on」狀況$s1和switch變量飽和之間的乘積--i。 這使得輕盈成爲咱們仍然須要應用完整配方的惟一組成部分
--j: calc(1 - var(--i));
background: hsl($h1,
calc(var(--i)*#{$s1}),
calc(var(--j)*#{$l0} + var(--i)*#{d1l}))
複製代碼
以上內容可在此演示中進行測試。 相似地,假設咱們想要font-size一些文本2rem在咱們的開關關閉(--i: 0)和10vw開關打開(--i: 1)時。應用相同的方法,咱們有:
font-size: calc((1 - var(--i))*2rem + var(--i)*10vw)
複製代碼
這意味着某些元件和其餘元件的開關關閉。例如,這能夠經過奇偶校驗來肯定。假設咱們但願全部偶數元素都旋轉而且具備橙色background而不是初始灰色元素
.box {
--i: 0;
--j: calc(1 - var(--i));
transform: rotate(calc(var(--i)*30deg));
background: hsl($h1,
calc(var(--i)*#{$s1}),
calc(var(--j)*#{$l0} + var(--i)*#{$l1}));
&:nth-child(2n) { --i: 1 }
}
複製代碼
由項目奇偶校驗觸發的切換(實時演示,因爲calc()不適用於角度值而在Edge中不能徹底正常工做)
在奇偶校驗的狀況下,咱們爲每隔一個項目(:nth-child(2n))打開開關,但咱們也能夠爲前七個項目(:nth-child(7n)),前兩個項目(:nth-child(-n + 2)),爲除了第一個和最後兩個(:nth-child(n + 3):nth-last-child(n + 3))以外的全部項目打開它。咱們也能夠僅針對標題或僅針對具備特定屬性的元素進行翻轉。
$c: #f90;
$h: round(hue($c)/1deg);
$s: round(saturation($c));
$l: round(lightness($c));
a {
--i: 0;
transform: scale(calc(1 + var(--i)*.25));
color: hsl($h, $s, calc(var(--i)*#{$l} + (1 - var(--i))*100%));
&:focus, &:hover { --i: 1 }
}
複製代碼
由於white任何hsl()具備亮度100%(色調和飽和度都可有可無)的值,咱們能夠經過始終保持:focus/ :hover狀態的色調和飽和度而且僅改變亮度來簡化事物。
由狀態變化觸發的切換(現場演示,因爲功能calc()內部不支持的值,Edge中功能不全scale())
另外一種可能性是切換由媒體查詢觸發,例如,當方向改變時或從一個視口範圍轉到另外一個視口範圍時。 比方說,咱們有white一個標題font-size的1rem最高320px,但隨後變爲橙色($c)和font-size變5vw,並開始與視縮放width。
h5 {
--i: 0;
color: hsl($h, $s, calc(var(--i)*#{$l} + (1 - var(--i))*100%));
font-size: calc(var(--i)*5vw + (1 - var(--i))*1rem);
@media (min-width: 320px) { --i: 1 }
}
複製代碼
ps:從可用性的角度來看,在網站上設置這樣的搜索框可能不是最好的主意,由於人們一般指望搜索框後面的按鈕觸發搜索,而不是關閉搜索欄,但它仍然是一個有趣的編碼練習,這就是爲何我選擇在這裏剖析它。
<input id='search-btn' type='checkbox'/>
<label for='search-btn'>Show search bar</label>
<input id='search-bar' type='text' placeholder='Search...'/>
複製代碼
咱們在這裏作的最初是隱藏文本input,而後在選中複選框以前將其顯示出來 - 讓咱們深刻了解它是如何工做的! 首先,咱們使用基本重置並flex在咱們input和label元素的容器上設置佈局。在咱們的例子中,這個容器是body,但也多是另外一個元素。咱們也絕對定位複選框並將其移出視線(視口外)。
*, :before, :after {
box-sizing: border-box;
margin: 0;
padding: 0;
font: inherit
}
html { overflow-x: hidden }
body {
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
min-width: 400px;
min-height: 100vh;
background: #252525
}
[id='search-btn'] {
position: absolute;
left: -100vh
}
複製代碼
咱們把複選框label變成一個大的綠色圓形按鈕,並使用一個大的負數值移動它的文本內容的視線text-indent和overflow: hidden。
$btn-d: 5em; /* 同上 */[for='search-btn'] {
overflow: hidden;
width: $btn-d;
height: $btn-d;
border-radius: 50%;
box-shadow: 0 0 1.5em rgba(#000, .4);
background: #d9eb52;
text-indent: -100vw;
cursor: pointer;
}
複製代碼
background
爲其聚焦狀態定義不一樣的光暈$btn-d: 5em;
$bar-w: 4*$btn-d;
$bar-h: .65*$btn-d;
$bar-r: .5*$bar-h;
$bar-c: #ffeacc;/* 同上 */
[id='search-bar'] {
border: none;
padding: 0 1em;
width: $bar-w;
height: $bar-h;
border-radius: $bar-r 0 0 $bar-r;
background: #3f324d;
color: #fff;
font: 1em century gothic, verdana, arial, sans-serif;
&::placeholder {
opacity: .5;
color: inherit;
font-size: .875em;
letter-spacing: 1px;
text-shadow: 0 0 1px, 0 0 2px
}
&:focus {
outline: none;
box-shadow: 0 0 1.5em $bar-c, 0 1.25em 1.5em rgba(#000, .2);
background: $bar-c;
color: #000;
}
}
複製代碼
此時,搜索欄的右邊緣與按鈕的左邊緣重合。可是,咱們想要一些重疊 - 假設重疊使得搜索欄的右邊緣與按鈕的垂直中線重合。鑑於咱們align-items: center在容器上有一個flexbox佈局(body在咱們的例子中),由咱們的兩個項目組成的組件(條和按鈕)保持水平中間對齊,即便咱們設置margin一個或另外一個或在這兩個項目之間。(在最左邊的項目的左側或最右邊的項目的右側是一個不一樣的故事,但咱們如今不會進入那個。)
這是.5*$btn-d半個按鈕直徑的重疊,至關於按鈕的半徑。咱們margin-right在欄上將其設爲負數。咱們還調整padding條形圖的右側,以便咱們補償重疊:
$btn-d: 5em;
$btn-r: .5*$btn-d;
/* 同上 */
[id='search-bar'] {
/* 同上 */
margin-right: -$btn-r;
padding: 0 calc(#{$btn-r} + 1em) 0 1em;
}
複製代碼
[for='search-btn'] {
/* 同上 */
position: relative;
}
複製代碼
在這種狀態下,條形和按鈕組件的總寬度是條形寬度$bar-w加上按鈕的半徑$btn-r(按鈕直徑的一半$btn-d),由於按鈕的一半重疊。在摺疊狀態下,組件的總寬度就是按鈕直徑$btn-d。
因爲咱們但願在從展開狀態到摺疊狀態時保持相同的中心軸,咱們須要將按鈕向左移動擴展狀態(.5*($bar-w + $btn-r))減去按鈕半徑($btn-r)的組件寬度的一半。 咱們稱之爲這種轉變$x,咱們在按鈕上使用減號(由於咱們將按鈕向左移動,左邊是x軸的負方向)。因爲咱們但願條形圖摺疊到按鈕中,咱們$x在它上面設置相同的偏移,可是在正方向上(由於咱們將條形圖移動到右邊的 x軸)。 當未選中複選框時,咱們處於摺疊狀態,而當未選中複選框時,咱們處於展開狀態。這意味着transform當沒有選中複選框時,咱們的欄和按鈕會被CSS移動,而且咱們當前將它們置於其中(沒有transform)。 爲了作到這一點,咱們--i在複選框後面的元素上設置了一個變量- 按鈕(使用label複選框建立)和搜索欄。此變量0處於摺疊狀態(當兩個元素都移位且未選中複選框時)並1處於展開狀態(當咱們的條和按鈕位於它們當前佔據的位置時,沒有移位,而且複選框被選中)
$x: .5*($bar-w + $btn-r) - $btn-r;
[id='search-btn'] {
position: absolute;
left: -100vw;
~ * {
--i: 0;
--j: calc(1 - var(--i)) /* 1 when --i is 0, 0 when --i is 1 */
}
&:checked ~ * { --i: 1 }
}
[for='search-btn'] {
/*同以前 */
transform: translate(calc(var(--j)*#{-$x}));
}
[id='search-bar'] {
/*同以前 */
transform: translate(calc(var(--j)*#{$x}));
}
複製代碼
可是咱們還有另外一個更大的問題:咱們能夠看到右側按鈕下方的欄杆。爲了解決這個問題,咱們在欄上設置clip-path了一個inset()值。這指定了一個剪切矩形,藉助於元素頂部,右側,底部和左側邊緣的距離border-box。剪切矩形以外的全部內容都會被剪切掉,只顯示內部的內容
在上圖中,每一個距離都從邊框的邊緣向內移動。在這種狀況下,他們是積極的。但它們也能夠向外移動,在這種狀況下它們是負的,而且剪切矩形的相應邊緣在元素以外border-box。 起初,您可能認爲咱們沒有理由這樣作,但在咱們的特定狀況下,咱們會這樣作! 咱們但願從top(dt),bottom(db)和left(dl)的距離是負的,而且足夠大以包含在該狀態中box-shadow的元素外部延伸的border-box距離,:focus由於咱們不但願它被剪切掉。因此解決方案是建立一個剪切矩形,邊緣在元素以外border-box在這三個方向。 與右邊的距離(dr)是摺疊狀況下的整個條寬$bar-w減去按鈕半徑$btn-r(未選中複選框--i: 0),而且0在展開的狀況下(選中複選框--i: 1)。
$out-d: -3em;
[id='search-bar'] {
/* 同以前 */
clip-path: inset($out-d calc(var(--j)*#{$bar-w - $btn-r}) $out-d $out-d);
}
複製代碼
因爲咱們不但願兩個便之間發生忽然變化,咱們使用transition:
[id='search-btn'] {
/* 同以前 */
~ * {
/* same as before */
transition: .65s;
}
}
複製代碼
咱們還但願咱們的按鈕background在摺疊的狀況下爲綠色(未選中複選框--i: 0),在展開的狀況下爲粉紅色(選中複選框--i: 1)。爲此,咱們使用與之前相同的技術:
[for='search-btn'] {
/* 同以前 */
$c0: #d9eb52; // green for collapsed state
$c1: #dd1d6a; // pink for expanded state
$h0: round(hue($c0)/1deg);
$s0: round(saturation($c0));
$l0: round(lightness($c0));
$h1: round(hue($c1)/1deg);
$s1: round(saturation($c1));
$l1: round(lightness($c1));
background: hsl(calc(var(--j)*#{$h0} + var(--i)*#{$h1}),
calc(var(--j)*#{$s0} + var(--i)*#{$s1}),
calc(var(--j)*#{$l0} + var(--i)*#{$l1}));
}
複製代碼
看看效果
咱們仍然須要作的是建立一個圖標,該圖標在摺疊狀態的放大鏡和展開狀態的「x」之間變形,以指示關閉動做。咱們使用:before和:after僞元素執行此操做。咱們首先肯定放大鏡的直徑以及圖標線寬度所表明的直徑。
$ico-d: .5*$bar-h;
$ico-f: .125;
$ico-w: $ico-f*$ico-d;
複製代碼
咱們絕對將僞元素放在按鈕中間,並考慮其尺寸。而後咱們把它們變成inherit父母的transition。咱們給:beforea background,由於這將是咱們的放大鏡的把手,使它成爲:after圓形border-radius並給它一個插圖box-shadow。
[for='search-btn'] {
/* 同以前 */
&:before, &:after {
position: absolute;
top: 50%; left: 50%;
margin: -.5*$ico-d;
width: $ico-d;
height: $ico-d;
transition: inherit;
content: ''
}
&:before {
margin-top: -.4*$ico-w;
height: $ico-w;
background: currentColor
}
&:after {
border-radius: 50%;
box-shadow: 0 0 0 $ico-w currentColor
}
}
複製代碼
咱們如今能夠在按鈕上看到放大鏡組件,爲了使咱們的圖標看起來更像放大鏡,咱們的translate兩個組件都向外放大了放大鏡直徑的四分之一。這意味着所述手柄平移向右,在正方向X經過軸.25*$ico-d與所述主要部分的左側,在負方向X以相同的軸線.25*$ico-d。 咱們還scale手柄(該:before僞元素)水平至其一半width相對於其右邊緣(這意味着一個transform-origin的100%沿X軸)。 咱們只但願在摺疊狀態下發生這種狀況(複選框未選中,--i是0,所以--j是1),所以咱們將轉換量乘以--j並用於--j調整比例因子:
[for='search-btn'] {
/* 同以前 */
&:before {
/* 同以前 */
height: $ico-w;
transform:
translate(calc(var(--j)*#{.25*$ico-d}))
scalex(calc(1 - var(--j)*.5))
}
&:after {
/* same as before */
transform: translate(calc(var(--j)*#{-.25*$ico-d}))
}
}
複製代碼
咱們如今處於摺疊狀態的放大鏡圖標:
因爲咱們但願旋轉兩個圖標組件45deg,咱們在按鈕自己上添加此旋轉:
[for='search-btn'] {
/* 同以前 */
transform: translate(calc(var(--j)*#{-$x})) rotate(45deg);
}
複製代碼
這仍然會離開擴展狀態,咱們須要將圓形:after僞元素轉換爲一條線。咱們經過縮放它順着這樣作X軸,將其border-radius從50%到0%。咱們使用的縮放係數是$ico-w咱們想要得到的線寬和$ico-d它在摺疊狀態下造成的圓的直徑之間的比率。咱們稱這個比例$ico-f。 由於咱們只但願作這在擴展狀態下,當複選框被選中,並--i是1,咱們使這兩個比例因子和border-radius依賴於--i和--j:
$ico-d: .5*$bar-h;
$ico-f: .125;
$ico-w: $ico-f*$ico-d;
[for='search-btn'] {
/* 同以前 */
&:after{
/* 同以前 */
border-radius: calc(var(--j)*50%);
transform:
translate(calc(var(--j)*#{-.25*$ico-d}))
scalex(calc(1 - var(--j)*.5))
}
}
複製代碼
嗯,差很少,但並不徹底。縮放也縮水了插圖box-shadow沿X軸,因此咱們進行了修復與第二插圖影子,咱們(當複選框被選中,並在擴展狀態下只能獲得--i是1),所以,它的傳播和α取決於--i:
$ico-d: .5*$bar-h;
$ico-f: .125;
$ico-w: $ico-f*$ico-d;
[for='search-btn'] {
/* 同以前 */
--hsl: 0, 0%, 0%;
color: HSL(var(--hsl));
&:after{
/* 同以前 */
box-shadow:
inset 0 0 0 $ico-w currentcolor,
/* collapsed: not checked, --i is 0, --j is 1
* spread radius is 0*.5*$ico-d = 0
* alpha is 0
* expanded: checked, --i is 1, --j is 0
* spread radius is 1*.5*$ico-d = .5*$ico-d
* alpha is 1 */
inset 0 0 0 calc(var(--i)*#{.5*$ico-d}) HSLA(var(--hsl), var(--i))
}
}
複製代碼
這給了咱們最終的結果!【本例完整源碼】
在這種狀況下,咱們的實際元素是前面較小的矩形,然後面的數字正方形和較大的矩形分別使用:before和:after僞元素建立。 數字方塊的背景是單獨的,並使用--slist對於每一個項目不一樣的中止列表變量進行設置。
<p style='--slist: #51a9ad, #438c92'><!-- 1st paragraph text --></p>
<p style='--slist: #ebb134, #c2912a'><!-- 2nd paragraph text --></p>
<p style='--slist: #db4453, #a8343f'><!-- 3rd paragraph text --></p>
<p style='--slist: #7eb138, #6d982d'><!-- 4th paragraph text --></p>
複製代碼
html {
--narr: 0;
--comp: calc(1 - var(--narr));
--wide: 1;
@media (max-width: 36em) { --wide: 0 }
@media (max-width: 20em) { --narr: 1 }
}
p {
--parity: 0;
&:nth-child(2n) { --parity: 1 }
}
複製代碼
數字方塊絕對定位,它們的位置取決於奇偶校驗。若是--parity開關關閉(0),則它們在左側。若是它在(1)上,那麼它們就在右邊。 一個值left: 0%沿着其父元素的左邊緣與數字方塊的左邊緣left: 100%對齊,而一個值沿着父元素的右邊緣對齊其左邊緣。 爲了使數字方塊的右邊緣與其父邊緣的右邊緣對齊,咱們須要從前一個100%值中減去本身的寬度。(請記住,%偏移量的值是相對於父級的尺寸。)
left: calc(var(--parity)*(100% - #{$num-d}))
複製代碼
... $num-d編號方塊的大小在哪裏。 在寬屏幕的狀況下,咱們還向外推送編號1em- 這意味着減去1em咱們迄今爲止對於奇數項目(--parity關閉開關)1em的偏移量,並添加到目前爲止偶數項目的偏移量(--parity開啓時) )。 如今問題是......咱們如何切換標誌?最簡單的方法是使用的權力-1。遺憾的是,咱們在CSS中沒有冪函數(或冪函數運算符),即便它在這種狀況下很是有用:
pow(-1, var(--parity))複製代碼
這意味着咱們必須使它與咱們所擁有的(加法,減法,乘法和除法)一塊兒工做,這致使了一個奇怪的小公式......可是,嘿,它有效!
--sign: calc(1 - 2*var(--parity))
複製代碼
left: calc(var(--parity)*(100% - #{$num-d}) - var(--wide)*var(--sign)*1em)
複製代碼
咱們還width使用這些變量來控制段落,而且max-width咱們但願它具備上限而且僅在窄case(--narr: 1)中水平地徹底覆蓋其父級:
width: calc(var(--comp)*80% + var(--narr)*100%);
max-width: 35em;
複製代碼
這font-size也取決於咱們是否處於狹窄的狀況(--narr: 1)或不是(--narr: 0):
calc(.5rem + var(--comp)*.5rem + var(--narr)*2vw)
複製代碼
......對於:after僞元素(後面較大的矩形)的水平偏移也是如此,由於它們0在窄狀況(--narr: 1)中,而非零偏移,$off-x不然(--narr: 0)
right: calc(var(--comp)*#{$off-x});
left: calc(var(--comp)*#{$off-x});
複製代碼
這個效果是經過一個連接元素和它的兩個僞元素在對角:hover和:focus狀態上對角滑動建立的。連接的尺寸是固定的,其僞元素也是固定的,設置爲它們的父對角線$btn-d(在寬度和高度造成的直角三角形中斜邊計算)水平和父height垂直。
該:before定位使得它的左下角恰逢其父,而:after被定位爲使得其右上角與其父一致。因爲二者都應與height其父級相同,所以經過設置top: 0和解決垂直位置bottom: 0。水平放置的處理方式與前一個示例徹底相同,使用--i切換變量來更改兩個僞元素之間的值,並使用--j其互補(calc(1 - var(--i))):
left: calc(var(--j)*(100% - #{$btn-d}))
複製代碼
咱們設定transform-origin的:before到它的左下角(0% 100%)和:after其右上角的(100% 0%),再次,與交換機的幫助--i和補充--j
transform-origin: calc(var(--j)*100%) calc(var(--i)*100%)
複製代碼
咱們將兩個僞元素旋轉到對角線和水平線之間的角度 $btn-a(也是由高度和寬度造成的三角形計算出來的,做爲二者之間比率的反正切)。經過這種旋轉,水平邊緣沿着對角線相交。 而後咱們按照本身的寬度向外移動它們。這意味着咱們將爲二者中的每個使用不一樣的符號,一樣取決於在:before和之間改變值的switch變量,:after就像前面的橫幅示例同樣:
transform: rotate($btn-a) translate(calc((1 - 2*var(--i))*100%))
複製代碼
在:hover和:focus,這個切換必須回去0。這意味着咱們經過互補乘以上面的平移量--q的開關變量--p這是0在正常狀態下和1在:hover或:focus狀態:
transform: rotate($btn-a) translate(calc(var(--q)*(1 - 2*var(--i))*100%))
複製代碼
爲了使僞元素在鼠標移出或失焦時以相反的方式滑出(不回溯它們進入的方式),咱們將switch變量設置--i爲--pfor :before的值,並將值設置--q爲for :after,反轉轉換的符號,確保只轉換transform屬性
在這種狀況下,咱們爲每一個項目(article元素)都有一個三行,兩列網格,第三行在寬屏幕場景中摺疊,第二列在窄屏幕場景中摺疊。在寬屏幕場景中,列的寬度取決於奇偶校驗。在窄屏場景中,第一列跨越元素的整個內容框,第二列具備寬度0。咱們在列之間也存在差距,但僅限於寬屏場景。【本例源碼】
$col-1-wide: calc(var(--q)*#{$col-a-wide} + var(--p)*#{$col-b-wide});
$col-2-wide: calc(var(--q)*#{$col-b-wide} + var(--p)*#{$col-a-wide});
$row-1: calc(var(--i)*#{$row-1-wide} + var(--j)*#{$row-1-norm});
$row-2: calc(var(--i)*#{$row-2-wide} + var(--j)*#{$row-2-norm});
$row-3: minmax(0, auto);
$col-1: calc(var(--i)*#{$col-1-wide} + var(--j)*#{$col-1-norm});
$col-2: calc(var(--i)*#{$col-2-wide});
$art-g: calc(var(--i)*#{$art-g-wide});
html {
--i: var(--wide, 1);
--j: calc(1 - var(--i));
@media (max-width: $art-w-wide + 2rem) { --wide: 0 }
}
article {
--p: var(--parity, 0);
--q: calc(1 - var(--p));
--s: calc(1 - 2*var(--p));
display: grid;
grid-template: #{$row-1} #{$row-2} #{$row-3}/ #{$col-1} #{$col-2};
grid-gap: 0 $art-g;
grid-auto-flow: column dense;
&:nth-child(2n) { --parity: 1 }
}
複製代碼
既然咱們已經設置了grid-auto-flow: column dense,咱們能夠在寬屏幕狀況下只設置第一級標題來覆蓋整個列(第二個用於奇數項,第一個用於偶數項),並讓第二個級別標題和段落文本填寫第一個可用單元格。
grid-column: calc(1 + var(--i)*var(--q));
grid-row: 1/ span calc(1 + 2*var(--i));
複製代碼
對於每一個項目,一些其餘屬性取決於咱們是否處於寬屏幕方案中。 在寬屏幕狀況下,垂直margin,垂直和水平padding值,box-shadow偏移和模糊都更大:
$art-mv: calc(var(--i)*#{$art-mv-wide} + var(--j)*#{$art-mv-norm});
$art-pv: calc(var(--i)*#{$art-pv-wide} + var(--j)*#{$art-p-norm});
$art-ph: calc(var(--i)*#{$art-ph-wide} + var(--j)*#{$art-p-norm});
$art-sh: calc(var(--i)*#{$art-sh-wide} + var(--j)*#{$art-sh-norm});
article {
margin: $art-mv auto;
padding: $art-pv $art-ph;
box-shadow: $art-sh $art-sh calc(3*#{$art-sh}) rgba(#000, .5);
}
複製代碼
咱們有一個非零border-width和border-radius寬屏幕的狀況
$art-b: calc(var(--i)*#{$art-b-wide});
$art-r: calc(var(--i)*#{$art-r-wide});
article {
border: solid $art-b transparent;
border-radius: $art-r;
}
複製代碼
在寬屏幕場景中,咱們限制項目width,但100%無論怎樣。
$art-w: calc(var(--i)*#{$art-w-wide} + var(--j)*#{$art-w-norm});
article {
width: $art-w;
}
複製代碼
padding-box
漸變的方向也隨奇偶校驗而變化:
background:
linear-gradient(calc(var(--s)*90deg), #e6e6e6, #ececec) padding-box,
linear-gradient(to right bottom, #fff, #c8c8c8) border-box;
複製代碼
以相似的方式,margin,border-width,padding,width,border-radius,background梯度方向,font-size或line-height對標題和段落文本還取決於咱們是不是在寬屏場景(在第一級標題的狀況下border-radius或background梯度方向,也在奇偶校驗)。
看效果: