並不簡單的翻頁時鐘(一):樣式篇(Flex佈局、line-height、data-set用法、css before after僞元素)

目錄

 

並不簡單的翻頁時鐘

   我以爲的翻頁時鐘

   實際上的翻頁時鐘

關鍵的知識點

效果展示

代碼解析

HTML

CSS

詳解CSS

1.display:flex 元素居中

2.:before 、:after僞元素

3.line-height=0的神奇

4.animation動畫

5.backface-visibility:hidden


github:https://github.com/taozhuowei/StoreMyToys/tree/master/FlipClock

 

並不簡單的翻頁時鐘

   我以爲的翻頁時鐘

翻頁時鐘=翻頁(transform:rotateX)+ 時鐘

   實際上的翻頁時鐘

翻頁時鐘=前邊的上半部分顯示當前時間的上半部分+前邊的下半部分顯示當前時間的下半部分+後邊的上半部分顯示下一秒的時間的上半部分+後邊的下半部分顯示下一秒時間的下半部分

好的我承認,這不是句人話。所以我畫了個圖

 

  

有點簡潔,但足夠理解翻頁時鐘大概是個什麼樣子。

但要把它做出來,還需要費一番功夫。

 

關鍵的知識點

  1. html中的data-set
  2. css line-height=0的用處
  3. css flex彈性佈局
  4. css :after :before僞元素
  5. css transform
  6. css backface-visibility
  7. css animation動畫

 

效果展示

       ScreenToGif這軟件真的挺好用...

代碼解析

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlipClock——翻頁時鐘</title>
    <link rel="stylesheet" href="ClockStyle.css">
</head>
<body>

<!--時鐘設置選項-->
<div id="option">
    <h6>時間格式:</h6>
    <span>24</span>
    <input type="checkbox" id="controlFormat" οnclick="toggleFormat()">
    <div class="checkButton"><label for="controlFormat"></label></div>
    <span>12 小時制</span>

    <h6>顯示秒 :</h6>
    <span> 顯示</span>
    <input type="checkbox" id="controlSecond" οnclick="toggleSecond()">
    <div class="checkButton"><label for="controlSecond"></label></div>
    <span>隱藏</span>

    <!--label 的 for attribute 綁定了 id 後,點擊label會選中對應id的checkbox,
            應用這個效果更改checkbox默認的樣式-->
</div>

<div id="flexContainer">
<!--時鐘整體背景-->
<div id="clockContainer">
    <!--時鐘數字,時間是兩位數,每一位一個div-->
    <!--data-number屬性實現簡單數據的存取
        用於css和js操作其中的值-->
    <!--時-->
    <!--第一位(從左到右)-->
    <div class="flipNumber" style="margin-left: 0">
        <div class="time front" data-number="0"></div>
        <div class="time back" data-number="1"></div>
    </div>
    <!--第二位-->
    <div class="flipNumber">
        <div class="time front" data-number="0"></div>
        <div class="time back" data-number="1"></div>
    </div>
    <!--分隔符-->
    <div class="divide">:</div>
    <!--分-->
    <!--第一位-->
    <div class="flipNumber">
        <div class="time front" data-number="0"></div>
        <div class="time back" data-number="1"></div>
    </div>
    <!--第二位-->
    <div class="flipNumber">
        <div class="time front" data-number="0"></div>
        <div class="time back" data-number="1"></div>
    </div>
    <!--分隔符-->
    <div class="divide second">:</div>
    <!--秒-->
    <!--第一位-->
    <div class="flipNumber second">
        <div class="time front" data-number="0"></div>
        <div class="time back" data-number="1"></div>
    </div>
    <!--第二位-->
    <div class="flipNumber second">
        <div class="time front" data-number="0"></div>
        <div class="time back" data-number="1"></div>
    </div>
</div>
</div>

<div id="twelve">
    <p id="ampm">AM</p>
</div>

<script src="Flip.js"></script>

</body>
</html>

HTML部分不是重頭戲,唯一與以往不同的則是data-number這個attribute的出現。

那麼這個data-number是什麼呢?

它是HTML5中出現的新特性,叫做data-set自定義屬性。它可以存放一個值,便於獲取。

那在這個翻頁時鐘中它的作用就是讓css和js獲取他的值,然後把時間的數字按位置傳給他

 

CSS

*{margin: 0 ; padding: 0}
body{background: #191919;overflow: hidden;}


/*時鐘設置選項*/
#option{
    position: absolute;     top: 30px;
    display: flex;  justify-content: center;    align-items: center;
    line-height: 50px;  text-align: center;
    height: 50px;
    font-size: 20px;     color: #717171;
}
#option h6{
    display: inline;
    font-size: 20px;
    margin-left: 20px;
}
#option span{font-size: 12px; margin-left: 10px}
/**
*更改checkbox樣式
 */
/*隱藏默認的checkbox複選框*/
#option input[type=checkbox]{visibility: hidden;}
/*滑動背景*/
.checkButton{
    position: relative;
    display: inline-block;
    width: 50px;    height: 20px;
    border-radius: 15px;    border: 2px solid #3b84dd;
    background: #191919;
}
/*滑軌*/
.checkButton:after{
    position: absolute; left: 5px;    top: 9px;
    z-index: 1;/*隱藏在滑塊下*/
    content: '';
    width:40px ;    height: 1px;
    background: white;
}
/*滑塊*/
#option  label{
    position: absolute;     left: 5px;
    z-index: 2;/*顯示在滑塊上*/
    width: 10px;    height: 10px;
    margin-top: 3px;
    border-radius: 100%;    border: 1px solid #25f7ff;
    background: #3b84dd;
    box-shadow: 1px 1px 3px #25f7ff;
    animation: bounceBack 1s forwards ease-in-out;
}
/*!!!!!必須使用+選擇器選擇相鄰的兄弟元素之後才能操作後邊的元素*/
#option input[type=checkbox]:checked+.checkButton label{
   animation: bounce 1s forwards ease-in-out;
}
@keyframes bounce {
    0%{left: 5px}
    90%{left: 40px}
    100%{left: 35px}
}
@keyframes bounceBack {
    0%{left: 35px}
    90%{left: 0}
    100%{left: 5px}
}



/*彈性盒容器*/
#flexContainer{
    display: flex;   /*子元素的佈局方式在父元素設置*/
    justify-content: center; /*水平居中*/
    align-items: center;/*垂直居中*/
    width: 100%;    height: 100vh;
    /*設置高度後align-items才生效*/
    /*1vh=1%屏幕高度*/
    background: #191919
}
/**
*時鐘背景
 */
#clockContainer{
    display: flex; justify-content: center; align-items: center;
    width: 95%;     height: 350px;
    border: 5px solid #5d5d5d;  border-radius: 15px;
    background: #242424;
}
/**
*翻頁數字容器
 */
.flipNumber{
    position:relative;   box-sizing: border-box;
    width: 14%;   height: 300px;    margin-left: 1.4%;
    text-align: center;     font-size: 300px;      line-height: 300px;
    background: #ffffff;
    box-shadow: 1px 1px 5px black;
}
/**
*時間分隔符
 */
.divide{
    width: 2%;  height: 100px;  line-height: 100px;
    margin-left: 1%;    font-size: 6rem;
    color:#717171;    text-align: center;
}

/**
*頁樣式,用前後僞元素實現翻頁的樣式
*前後僞元素的值爲.time中data-number屬性的值
*before是上半頁,after是下半頁
*僞元素一個:是css2寫法,兩個::是css3寫法
 */
.time::before, .time::after{
    content: attr(data-number);
    position: absolute;     left: 0;    right: 0;
    overflow: hidden;
    color: #717171;     background: #191919;
    perspective: 100px;      -webkit-perspective: 160px;
}
.time::before{
    top:0;   bottom: 50%;
    border-bottom: 1px solid #717171;/*轉軸*/
}
.time::after{
    top:50%;    bottom: 0;
    line-height: 0;
}
/*翻轉前*/
.flipNumber .front::after , .flipNumber .back::before{z-index: 1;}
.flipNumber .back::after{
    z-index: 2;
    transform-origin: center top;    -webkit-transform-origin: center top;
    transform: rotateX(0.5turn);/*轉半圈*/     -webkit-transform: rotateX(0.5turn);
}
.flipNumber .front::before{z-index: 3;}

/*翻轉後*/
.flipNumber.running .front::before{
    transform-origin: center bottom;    -webkit-transform-origin: center bottom;
    animation: frontFlipDown 0.6s ease-in-out;      -webkit-animation: frontFlipDown 0.6s ease-in-out;
    box-shadow: 0 -2px 6px rgba(255, 255, 255, 0.3);
    backface-visibility: hidden;/*隱藏背面*/     -webkit-backface-visibility: hidden;
}
.flipNumber.running .back::after{
    animation: backFlipDown 0.6s ease-in-out;   -webkit-animation: backFlipDown 0.6s ease-in-out;
}

/*十二小時制下提示上下午*/
#twelve{
    display: none;
    position: absolute;     bottom: 100px;      right: 40px;
    width: 100px;   height: 50px;   line-height: 50px;
    text-align: center;
    border: 5px solid #5d5d5d;  border-radius: 15px;
    font-size:25px;     color: #717171;
}



/**
*動畫
*/
@keyframes frontFlipDown {
    to{transform:rotateX(0.5turn)}
}
@keyframes backFlipDown {
    to{transform: rotateX(0)}
}

@-webkit-keyframes frontFlipDown {
    to {-webkit-transform: rotateX(0.5turn);}
}
@-webkit-keyframes backFlipDown {
    to {-webkit-transform: rotateX(0);}
}

一般的項目CSS往往只是起到修改樣式,很少着墨去詳細講它。

而翻頁時鐘不一般,所謂翻頁時鐘=翻頁+時鐘。

翻頁就是CSS , 而時鐘則是JavaScript

這篇文章我們先不討論JavaScript,重點聚焦這個CSS

 

詳解CSS

1.display:flex 元素居中

/*彈性盒容器*/
#flexContainer{
    display: flex;   /*子元素的佈局方式在父元素設置*/
    justify-content: center; /*水平居中*/
    align-items: center;/*垂直居中*/
    width: 100%;    height: 100vh;
    /*設置高度後align-items才生效*/
    /*1vh=1%屏幕高度*/
}
/**
*時鐘背景
 */
#clockContainer{
    display: flex; justify-content: center; align-items: center;
}
/**
*翻頁數字容器
 */
.flipNumber{
  
}

在上面這段代碼中(無關的代碼被我刪了),flexContainerclockContainer 和 flipNumber 三個盒子爲父子關係(爺孫?)。

flex的一個直觀的特性是,明明是規定子元素的佈局,樣式卻要寫在父元素裏面(像極了爲你好的父親......)

那麼,如何實現居中呢?只需兩步

1.justify-content :規定元素(子元素)在彈性容器(父容器)內的主線(x軸)上的對齊方式,center爲水平居中

2.align-content:規定元素在彈性容器內的垂直軸(y軸)上的對齊方式,center爲垂直居中

簡單兩步,水平垂直居中就搞定了,而垂直居中不僅可以寫在父元素內,也可以將align-self寫在子元素內規定自己的對齊方式

這裏再簡單介紹一下出現的 vh 單位 ,viewheight ,即屏幕高度,也就是鋪滿整個屏幕,很好理解。

 

2.:before 、:after僞元素

在css3中,這兩個僞元素被寫作 ::before 和 ::after 便於和僞類進行區分 ,一個:有助於瀏覽器兼容性

我們首先先回顧一下HTML中的結構

<!--時-->
    <!--第一位(從左到右)-->
    <div class="flipNumber" style="margin-left: 0">
        <div class="time front" data-number="0"></div>
        <div class="time back" data-number="1"></div>
    </div>

這一段是小時的第一位(從左到右數)的HTML結構。

我們注意到他們的data-number分別是0和1。0是當前時間,1是接下來的時間(下一秒),在文章後續也用0代表現在,1代表下一秒。

在HTML中,0和1共有time類,而0單獨設置了front ,1單獨設置了back,很好理解,一前一後。

我們來看CSS

.time::before, .time::after{
    content: attr(data-number);
    position: absolute;     left: 0;    right: 0;
    overflow: hidden;
    color: #717171;     background: #191919;
    perspective: 100px;      -webkit-perspective: 160px;
}
.time::before{
    top:0;   bottom: 50%;
    border-bottom: 1px solid #717171;/*轉軸*/
}
.time::after{
    top:50%;    bottom: 0;
}

首先,創建僞類,content設置爲data-number這個attribute的值(派上用場了),絕對定位並讓其與本體完全重合。

 

效果似乎不太理想,而且應該在後邊的1跑到了前邊。(由於後渲染的1又是絕對定位的緣故)另外,這個1,似乎有些奇怪。

不要急,我們繼續調整。改變一下他們的層級(z-index)

/*翻轉前*/
.flipNumber .front::after , .flipNumber .back::before{z-index: 1;}
.flipNumber .back::after{
    z-index: 2;
    transform-origin: center top;    -webkit-transform-origin: center top;
}
.flipNumber .front::before{z-index: 3;}

/*翻轉後*/
.flipNumber.running .front::before{
    transform-origin: center bottom;    -webkit-transform-origin: center bottom;
    animation: frontFlipDown 0.6s ease-in-out;      -webkit-animation: frontFlipDown 0.6s ease-in-out;
    box-shadow: 0 -2px 6px rgba(255, 255, 255, 0.3);
    backface-visibility: hidden;/*隱藏背面*/     -webkit-backface-visibility: hidden;
}
.flipNumber.running .back::after{
    animation: backFlipDown 0.6s ease-in-out;   -webkit-animation: backFlipDown 0.6s ease-in-out;
}

 然後,他長這樣

這個時候,耐心已經所剩無幾,不過不要緊,幹就完了!

這個時候我們應該把1的下半部分翻上去

.flipNumber .back::after{
    z-index: 2;
    transform-origin: center top;    -webkit-transform-origin: center top;
    transform: rotateX(0.5turn);/*轉半圈*/     -webkit-transform: rotateX(0.5turn);
}

 添加一句transform:rotateX(0.5turn)就好了。(0.5turn表示轉半圈)

現在層級關係對了,可是這個錯位的0並不是我們想要的。

於是,讓我們請出下一個主角。

 

3.line-height=0的神奇

在之前的實踐中,line-height往往用來實現文字的居中對齊。沒曾想到,他還可以等於0。並且還辣麼的好用。

讓我們加上line-height=0,看看效果

可是,爲什麼呢?

 我們在這裏不從字面意義上把它理解爲行高,而是將他理解爲設置基線(元素的中心水平線)的位置。

line-height=0時,基線的位置在盒子的頂部,那麼留在盒子裏的自然就是元素的下半部分了。


爲了方便理解上面幾點的位置關係,我又獻上了我粗糙的畫風

 

側視圖

 

好吧,可能你更懵了。不如,試試折個紙,這樣理解的會更快

我就不廢紙了,我們繼續說。

 

4.animation動畫

如果要我說最喜歡CSS3的哪個新特性,那答案一定是CSS的動畫。(雖然我做的還不咋地......)

但是讓時鐘翻個頁,倒也不難

/**
*動畫
*/
@keyframes frontFlipDown {
    to{transform:rotateX(0.5turn)}
}
@keyframes backFlipDown {
    to{transform: rotateX(0)}
}

@-webkit-keyframes frontFlipDown {
    to {-webkit-transform: rotateX(0.5turn);}
}
@-webkit-keyframes backFlipDown {
    to {-webkit-transform: rotateX(0);}
}

在需要動畫的元素裏寫 animation :動畫名 持續時長; 就可以爲元素簡單的綁定一個動畫,你還可以設置動畫結束後和開始前的狀態,動畫的速度等細節。

之後,用@keyframes 動畫名就可以開始創作動畫了。

最常規的寫法是包含from和to的。也可以使用百分比來控制動畫的關鍵幀。

可是問題又來了。時鐘翻頁的時候,前邊0的上半部翻下來還是可以看見,這可不好。

不怕,山人自有妙計。

 

5.backface-visibility:hidden

字面意思及其清晰,懂英文的一看,不用我說就能明白。

背部不可見。

一句搞定!

 


那麼到此爲止,樣式部分就講完了。(emmmm...關於那個按鈕的部分我會單獨出一篇文章)

歡迎關注,等待下一篇的JavaScript部分以及後續....

(網課害人,更新遙遙無期)

 

喜歡的話,點個關注。

如有紕漏,歡迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章