FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...

未完待續

背景

現在css3愈來愈興旺,focus-within等屬性也已最先在Chrome獲得支撐。假如有精彩的css功底,一點點ps妙技,你也能用css3合營原生html標籤寫出優異的框架。經由過程對css3的實踐,我發明自定義原生控件並不是什麼難事,因而小試牛刀寫了個 純CSS3完成Material Design

關於

關於本文的一切代碼完成,以及更多純css控件,請在 https://github.com/Seasonley/… 中檢察。
本文針對本人開闢的純css框架Sultana中主要的幾個經常運用組件舉行深入分析,與人人議論怎樣一步步構想完成,包含:

  1. var(–x) 寫柵格體系
  2. focus-within & a & input 寫下拉挑選控件
  3. input radio & date 完成日期挑選控件
  4. background linear-gradient:一個有爭議的scroll_indicator完成體式格局
  5. css動畫 + css變量 寫自適應大小輪播控件
  6. 導航欄之:focus-within 側邊欄導航滑出
  7. 導航欄之:summary摺疊導航,秒殺bulma靜態款式
  8. input range 能夠寫五星好評啦
  9. 友愛的tooltip,transform 大法

1.var(–x) 寫柵格體系 (源碼

盡人皆知Bootstrap柵格體系 供應了差別裝備寬度下的12柵格,那末我們怎樣打敗Bootstrap,用css3變量完成一個壯大的自適應柵格呢?

1.1 聲明差別裝備的css變量稱號

假定我們斟酌4種裝備,以下方表格所示。模仿Bootstrap我們將他們命名為sm,md,lg。

su-col特小屏(-,480px)小屏(480px,720px)中屏(720px,1200px)大屏(1200px,+)牢固數值(掩蓋以上變量)
css變量名--sm--md--lg--col
範例 int(1 , 2 , … , 12) int(1 , 2 , … , 12) int(1 , 2 , … , 12) number(90% , 0.3 , …)

那末col干什麼用?終究容器的寬度應當轉換成單一變量,前面3者都是輔佐。假定我們的規劃以下

<div su-row>
    <div su="primary" su-col style="--sm:3;--md:4;--lg:12;--sm-v:hidden"></div>
    <div su="light" su-col style="--sm:3.2;--md:4.5;--lg:12;"></div>
    <div su="info" su-col style="--sm:3.3;--lg:12;"></div>
</div>
<div su-row>
    <div su="warning" su-col style="--col:0.22;--sm-d:none"></div>
    <div su="info" su-col style="--col:0.33;"></div>
    <div su="primary" su-col style="--col:0.44;"></div>
</div>  

1.2 –col: calc(var(–md) / 12)

我們願望差別裝備的col寬度根據變量自適應,還能夠有displayvisiblity這些輔佐操縱,接下來看css完成,以-md為例子,代碼以下。

@media screen and (min-width: 721px) {
    div[su-col] {
        --col: calc(var(--md) / 12);
        display: var(--md-d);
        visibility: var(--md-v);
    }
}

接着只需在su-col中運用var(–col)就可以搞定自適應。代碼以下。

div[su-col] {
 width: calc(100% * var(--col));
}

是不是是很輕鬆,每一行都是英華。假如直接用--col,那適配變量失效,這通經常運用在不須要適配的場景下。
《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》

1.3 flex規劃簡寫

flex規劃逐步替代浮動規劃,那末自定義一些簡寫的class來讓代碼看起來更整齊也是異常有必要的。本人供應一個完成體式格局,並不一定受歡迎,不感興趣能夠跳過。

flex屬性縮寫參照

  • j=justify,a=algin,c=content
  • 100,001,010,101=start,end,center,between
  • -row=row-reverse
  • -warp=warp-reverse
  • !warp=no-warp

html示例

《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》

2. focus-within & a & input 寫下拉挑選控件 (源碼)

2.1focus-within這麼用

看這個題目就秘制重量級,下拉控件不好辦,許多css框架都只能div套啊套的,再用js搞點數據綁定。不過既然有focus-within。我們先腦補一下,點擊這個a標籤,a+div里的input[radio]都顯現,不focus則隱蔽。這處理了下拉動畫結果。那末鼠標經由要高亮,input又不能寫筆墨,也沒有偽元素能夠弄dataset,那隻好input+span組合一下了。假定html部份代碼以下。

<button su="outlined -">
    <a href="javascript:">(blank)</a>
    <ul>
        <input checked type="radio" name="ra" value=""/>
        <span>(blank)</span>
        <input title="A.dada" type="radio" name="ra" value="1"/>
        <span>A.da</span>
        <input title="B.huha" type="radio" name="ra" value="2"/>
        <span >B.la</span>
    </ul>
</button>

如許看來好像能寫個導航欄了呢,多個按鈕拼一下什麼的。

2.2選中的移到最上面

如題目,接下來處理選中項的顯現,很簡單,absolute相對定位嘛。

button[su~="-"] input:checked+span {
    position: absolute;
    top: 0px;
}

《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》

默許來個value=””的,筆墨為(blank),算是很為難的委屈求全了,瑕玷是選中項不再在下拉列表中顯現了,其次筆墨是不能點擊選中的,只能點空白處。

3. input radio & date 完成日期挑選控件 (源碼)

3.1 31個input

有意義,看完上面的奇葩完成select,你應當對這個更感興趣一點。作為一個前端你不會本身寫日期控件,你好意義嗎你?成天用jquery-datepicker你的良知不會痛嗎?這回我們再尬一回,用css和少許的js代碼來完成。尬在哪呢?31個input[radio],誰會用啊,能夠只需那些禁用js的瀏覽器的需求方須要這個。

3.2 少許的js

oninput的時刻須要算出閏年+這個月1號禮拜幾,把它放到dataset,由css羅列1號的7種禮拜狀況,css羅列大月小月和閏年2月。(這行形貌最主要)
代碼完成以下

html

<form oninput="ymd.value=y.value+'-'+('0'+m.value).slice(-2)+'-'+d.value;ymd.dataset.leap=(y.value % 4 == 0) && (y.value % 100 != 0 || y.value % 400 == 0);ymd.dataset.day=new Date(y.value+'-'+('0'+m.value).slice(-2)+'-1').getDay()" 
onclick="ymd.value=y.value+'-'+('0'+m.value).slice(-2)+'-'+d.value"
onmouseover="ymd.dataset.day=new Date(y.value+'-'+('0'+m.value).slice(-2)+'-1').getDay()">
    <label su-date>
            <input su type="date" name="ymd" readonly>
            <div>
                <input name="y" type="number" min="1970" max="3000" value="2000" 
                onchange="this.setAttribute('value', this.value)">
                <input name="m" type="number" min="1" max="12" value="1" 
                onchange="this.setAttribute('value', this.value)">
                <div>
                    <input name="d" type="radio" value="01" checked>
                    <input name="d" type="radio" value="02">
                    ...
                    

css

label[su-date] input[type="number"][value="2"]+div input[type="radio"]:last-of-type,
label[su-date] input[type="number"][value="4"]+div input[type="radio"]:last-of-type,
label[su-date] input[type="number"][value="6"]+div input[type="radio"]:last-of-type,
label[su-date] input[type="number"][value="9"]+div input[type="radio"]:last-of-type,
label[su-date] input[type="number"][value="11"]+div input[type="radio"]:last-of-type,
label[su-date] input[type="number"][value="2"]+div input[type="radio"][value="30"],
label[su-date] input[type="number"][value="2"]+div input[type="radio"][value="29"] {
    display: none
}

label[su-date] input[name="ymd"][data-leap="true"]+div input[type="radio"][value="29"] {
    display: block
}

label[su-date] input[name="ymd"][data-day="1"]+div input[type="radio"][value="01"] {
    margin-left: calc(0 * var(--x2))
}

label[su-date] input[name="ymd"][data-day="2"]+div input[type="radio"][value="01"] {
    margin-left: calc(1 * var(--x2))
}

label[su-date] input[name="ymd"][data-day="3"]+div input[type="radio"][value="01"] {
    margin-left: calc(2 * var(--x2))
}

label[su-date] input[name="ymd"][data-day="4"]+div input[type="radio"][value="01"] {
    margin-left: calc(3 * var(--x2))
}

label[su-date] input[name="ymd"][data-day="5"]+div input[type="radio"][value="01"] {
    margin-left: calc(4 * var(--x2))
}

label[su-date] input[name="ymd"][data-day="6"]+div input[type="radio"][value="01"] {
    margin-left: calc(5 * var(--x2))
}

label[su-date] input[name="ymd"][data-day="0"]+div input[type="radio"][value="01"] {
    margin-left: calc(6 * var(--x2))
}

瑕玷:老長老長的html和css…
預覽:
《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》

4. background linear-gradient:一個有爭議的scroll_indicator完成體式格局

在掘金上看到網易考拉前端寫的CSS Scroll Indicator —— 純CSS 轉動指示器,完成體式格局很奇妙,經由過程直角三角形背景的頂部界面與頁面高度相關性製作一個現實上滾背景,看起來在伸縮進度條的結果。該文提到已知的2個瑕玷。

  1. 文檔內容太少(高度太小)的話,進度條呈箭頭形,不美觀(可斟酌加毛玻璃結果來弱化)
  2. background-size: 100% calc(100% - 99vh); 中的99vh是相對值,如果視窗高度比較小,進度條會填不滿進度條槽(可斟酌加min-height來弱化)

那它放到現實項目中結果怎樣呢,本人實驗了一下,在篇幅很長,標籤元素嵌套許多的頁面中到場scroll_indicator,轉動過程當中背景重繪非常卡,以至於元素按鈕點開都不能實時相應。所以假如是純文本博客或許說明文檔之類的元素標籤和css充足少的狀況下,能夠運用該體式格局完成靜態文檔的進度條,龐雜的dom和css狀況下不發起運用。當本人放到本身項目中測試時,按住轉動條高低疾速拖動時,轉動條都是跳幀的。。。

5. css動畫 + css變量 寫自適應大小輪播控件 (源碼)

Bootstrap輪播控件經由過程js完成,那末css能完成嗎,顯然是能夠的。完成到什麼程度呢?本人羅列以下能夠完成功用:

  1. 自適應屏幕,寬高可控
  2. 輪播圖片有零丁的自定義題目標籤(不能是偽元素)
  3. 要有圓點指示器,圓點大小可自定義,高亮的圓點代錶轉動到第幾章圖
  4. 指示器可點擊,跳轉到對應的圖
  5. 鼠標hover在控件上停息輪播

看上去很全了,本人講一下詳細思緒。
輪播須要假定在absolute的畫布上橫向轉動,轉變元素的程度位移數值margin-left來完成。經由過程css關鍵幀動畫能完成。以下:

@keyframes rua {
     0%,20% {margin-left: 0}
    25%,40% {margin-left: calc(0px - 1*var(--w))}
    45%,60% {margin-left: calc(0px - 2*var(--w))}
    65%,80% {margin-left: calc(0px - 3*var(--w))}
    85%,100%{margin-left: calc(0px - 4*var(--w))}
}

指示器能夠同新標籤,但不能像題目元素包裹在圖片容器內,由於指示器是不能轉動的。因而相對定位相關於悉數控件容器內就可以夠。html代碼以下:

<aside su="." style="--w:400px;--h:300px;--p:20px;">
    <button></button><button></button>
    <button></button><button></button>
    <button></button>
    <ul>
        <li style="background:gray;"><a>題目1</a></li>
        <li style="background:orange;"><a>題目2</a></li>
        <li style="background:teal;"><a>題目3</a></li>
        <li style="background:blue;"><a>題目4</a></li>
        <li style="background:black;"><a>題目5</a></li>
    </ul>
</aside>

在上述5點功用中,
<1><3>能夠用css變量處理,比方--w:400px;--h:300px;--p:20px;完成了寬度400px,高度300px,圓點大小直徑20px的控件。
<2>零丁設a標籤
<4>用focus-within完成點擊后css動畫停息在某個關鍵幀,瑕玷一是:有幾個圖就要寫幾個動畫,瑕玷二是:點擊后雖然選中了,但鼠標移出控件不會繼承轉動,在控件外點擊會跳回初始動畫關鍵幀。以一個圖的動畫為例:

aside[su~="."] button:nth-child(5):focus-within~ul {
    animation: ma5 .5s ease-out forwards;
}
@keyframes ma5 {
    100% {margin-left: calc(-4 * var(--w))}
}

<5>經由過程hover的停息css動畫來掌握

aside[su~="."] button:hover,
aside[su~="."] ul:hover {
    will-change: transform;
    animation-play-state: paused;
}

團體結果還不錯:
《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》

進階計劃 css-scroll-snap

6. 導航欄之:focus-within 側邊欄導航滑出 (源碼)

在沒湧現focus-within之前,用鄰近元素挑選器+css能完成純css的下拉選項的導航欄,在這裏就不多睜開了。末了一個focus-within的魔法魅力。我們須要完成相似android側邊欄滑出的結果。
《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》

網上已有人完成了《CSS :focus-within》 Airen的博客,那我就講一下他是怎樣完成的。該文頂用到了挪動端延伸出的冷門css屬性touch-action: manipulation。CSS屬性 touch-action 用於指定某個給定的地區是不是許可用戶操縱,以及怎樣相應用戶操縱(比方瀏覽器自帶的划動、縮放等)(MDN)。挪動端300ms耽誤,就可以夠運用 touch-action: manipulation; 來處理。我們只須要完成點擊左上角按鈕后滑出菜單,聲明一下按鈕點擊不影響其手勢操縱就好了。

本控件只需完成focus-within后動畫彈出菜單。落空核心的時刻彈回去就好了。實在和touch-action沒什麼關聯。先定義菜單部份的css,將其扔到左側屏幕外(margin或許transform都行):

#nav-content
transform: translateX(-100%);
transition: transform .3s;

再定義選中后的菜單:

#nav-container:focus-within #nav-content {
    transform: none;
}

大抵思緒就是如許。講了那末多focus-within的相關內容,但國內部份webkit內核瀏覽器還在50以下的階段,還請列位運用chrome63以上版本接見。

7. 導航欄之:summary摺疊導航,秒殺bulma靜態款式 (源碼)

先來看看 bulma 是怎樣寫的
《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》

ul li p a 互相嵌套,沒錯是個很好的完成體式格局,假如加focus-within和相鄰元素挑選也能完成點擊后的動畫結果,不過要輕微轉變一下嵌套體式格局,但這不是本文的議論重點。focus-within有它的瑕玷,關於一個菜單來講,用戶非常困難睜開找到了,一點別的菜單層級,之前的全縮回去了,那怎樣行。必需要有一個睜開後點擊再縮回去的功用。

這就要引出奇異的summary標籤,只用合營details用時,當details內的summary元素被點擊時,details悉數顯現,再次點擊縮起只剩summary。在張鑫旭大神的藉助HTML5 details,summary無JS完成種種交互結果中提到了許多可完成的控件,樹,菜單等等。

本人模仿Bulma用summary特徵完成了一個帶動畫的導航菜單,代碼還算文雅,以下圖所示。
《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》

進階 css-position-sticky

8. input range 能夠寫五星好評啦 (源碼)

一個原生的局限輸入控件,在瀏覽器是非常大略的,所以並木有人想去用原生的。我們看一下螞蟻金服前端團隊是怎樣完成的(ant.desgin):

《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》

貌似是section>ul>li,再加class示意zero full 的小星星,移上去另有動畫,又是一堆class。我們先不斟酌動畫的完成,先來吐槽這個dom多了以後襯着class的機能題目,li內里又有2個半的小星星來支撐step=0.5的打分,這些原生瀏覽器都支撐的屬性何須用2+5*3=17個dom元素天生?言而不行假把式,趕忙拉出個代碼來溜溜。

首先是html,就一行~

<input su="star" value="1" min="1" max="5" type="range" onchange="this.setAttribute('value', this.value)" />

其次是css:

input[type="range"][su~="star"] {
    cursor: pointer;width: calc(16px * 5);height: 16px;
    -webkit-appearance: none;-webkit-mask-image: var(--star);
    background: linear-gradient(to right, var(--Primary), var(--Primary)), 
                linear-gradient(to right, var(--Gray), var(--Gray));
    background-repeat: no-repeat;
}

input[type="range"][su~="star"][value="1"] {
background-size: calc(16px * 1) 16px, calc(16px * 5) 16px;
}

input[type="range"][su~="star"][value="2"] {
    background-size: calc(16px * 2) 16px, calc(16px * 5) 16px;
}
...

經由過程差別屬性的input背景,將小星星呈現出差別的色彩,linear-gradient襯着出進度,假如是半星也好辦,在step=0.5的狀況下多羅列幾個.5的分數狀況就行。結果以下:
《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》
進階:表開闢注意事項

9. 友愛的tooltip,transform 大法 (源碼)

transform在上文的完成android滑動菜單有提到,再擴大一下它的其他用處。我們能夠用來寫tooltip。關於一個title屬性的標籤,盡人皆知鼠標懸浮會顯現一個方框,內容是title屬性的值。那末偽元素的content: attr正好能合營transform 組織差別方位的tooltip。

[su-hint~="bottom"]:after {
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
}

[su-hint~="bottom"]:hover:after {
    transform: translateX(-50%) translateY(8px);
}

[su-hint~="right"]:after {
    margin-bottom: -14px;
    left: 100%;
    bottom: 50%;
}

[su-hint~="right"]:hover:after {
    transform: translateX(8px);
}

《FE.CSS-Sultana跋文:純css也能寫col,select,datepicker,carousel...》

github上早有壯大的自定義tooltip了,假如你情願捐軀before after 2個偽元素完成tooltip的氣泡和箭頭,發起運用hint.css

    原文作者:seasonley
    原文地址: https://segmentfault.com/a/1190000014751508
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞