---
# System prepended metadata

title: 五金行日曆

---

# 五金行日曆

![](https://i.imgur.com/CJ4Hpge.jpg =600x)

> [FIVE METAL SHOP CALENDAR 五金行日曆 2020](https://www.shoppingdesign.com.tw/post/view/4618/)

一直很喜歡這本可愛又充滿設計感的傳統日曆，但是礙於懶人個性一定放到明年還在第一頁
太可愛了也會捨不得撕，趁著這次練習 Date()，不如就自己手刻一本。



## 重點語法
撰寫語法使用 SASS，如果看不習慣的話可以轉譯成 CSS
主要會頻繁使用到以下語法：
* **flex**
* **transform: translate、skew、scale**
* **background: linear-gradient**
* **box-shadow**
* **text-shadow**

**<font color="red">＊這次 CodePen 設定 CSS Base 有開啟 Reset</font>**

## 一、分析架構
開始切版之前，首先要分析架構
就像蓋房子一樣，地基要打得穩，房子才能蓋的堅固
如果是初學者，建議可以試著在紙上畫出網頁架構

**外框容器**
* calendar：日曆主體，用 `after` 製作厚度
* header：上方裝訂，用 `before` 製作厚度
* hook：掛鉤部分
* body：主要呈現內容

![](https://i.imgur.com/DU1OuvE.jpg =500x)


**資料內容**
* month：上方當月月份
* date：今天日期
* fullMonth：小月曆
* week：星期、農曆
* icons：小圖示

![](https://i.imgur.com/dkzGprg.jpg =500x)



## 二、HTML 切版
框架分析完後，就可以開始切框架
切版時先放入靜態資料，模擬放入資料的狀況，調整樣式也較準確

<font color="red">**＊**</font> 可以在 css 最上方加入這段，自動把所有物件加上外框
```
* { outline: 1px solid red }
```

```htmlmixed=
<div id="app">
    <div class="calendar">
      <div class="header">
        <div class="pin"></div>
        <p>2020</p>
        <div class="pin"></div>
      </div>
      <div class="hook"></div>
      <div class="body">
        <div class="month">
            <p>8</p>
            <p>Aug</p>
        </div>
        <div class="date">11</div>
        <div class="footer">
          <div class="fullMonth">
            <div class="title">August</div>
            <table>
              <tr>
                <th>...</th>
            </tr>
            <tr>
                <td>...</td>
            </tr>
            </table>
          </div>
          <div class="week">
            <p class="en">tuseday</p>
            <p class="day">星期二</p>
            <p class="lunar">農6-22</p>
          </div>
          <div class="icons">
            <div class="material-icons">wb_sunny</div>
            <div class="material-icons">cloud</div>
            <div class="material-icons">brightness_1</div>
          </div>
        </div>
      </div>
    </div>
</div>
```
**小月曆** 的部分會有字體沒辦法再縮小的問題：
1. 可以用 `transform: scale` 來縮小整體
2. 再用 `transform-rigin` 調整中心位置
3. 加上 `ransform: translate` 調整位移

初步完成如下圖：

![](https://i.imgur.com/oH2UXha.png =500x)


## 三、用偽元素製作細節
框架完成後，為避免框架上有太多元件
裝飾性質的東西可以用 `before`、`after` 來完成 ( 下圖綠色部分 )
**月曆厚度** 可以用 `transform: skew` 製作傾斜效果
先用 `scale` 放大會比較好對齊，邊調整位置和角度，讓兩條厚度可以接在一起

![](https://i.imgur.com/6yZU2u4.png =500x)


## 四、陰影運用
陰影 `box-shadow` 的運用是繪製實物時最重要的部分，可以分為幾種方式：

### 基本陰影堆疊
陰影可以無限堆疊，並且設定不同位移、強度、顏色
依照畫面的需求堆疊出陰影，增加立體感

![](https://i.imgur.com/pRY5Bhs.png =500x)

### 利用陰影製作重複元素
陰影除了堆疊，也可以用來製作複製元素
利用 **位移變化** 和相同 **陰影強度(模糊效果)**，可以做出頁邊色票
魔鬼藏在細節中，切版最重要的就是細心和耐心
推薦文章： [CSS 模糊效果](https://www.oxxostudio.tw/articles/201407/css-blur.html)

```sass
box-shadow: 0 0 2px 1px #79746B, 1px*1 -22px*1 2px 1px #A07F2E, 1px*2 -22px*2 2px 1px #884940, 1px*3 -22px*3 2px 1px #216164, 1px*4 -22px*4 2px 1px #853555, 1px*5 -22px*5 2px 1px #628279, 1px*6 -22px*6 2px 1px #493B62, 1px*7 -22px*7 2px 1px #772C22, 1px*8 -22px*8 2px 1px #436251, 1px*9 -22px*9 2px 1px #0B6575, 1px*10 -22px*10 2px 1px #99834C, 1px*11 -22px*11 2px 1px #4D4229, 1px*12 -22px*12 2px 1px #89425A, 1px*13 -22px*13 2px 1px #5A4C6A, 1px*14 -22px*14 2px 1px #975B4B
```

![](https://i.imgur.com/WVFgEVM.png =500x)


## 五、抓取時間
加上顏色和相關細節設定後，就要來加入時間內容
### 日期、星期
```javascript=
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
const days = ['日', '一','二','三','四','五','六']
const en = ['sunday', 'monday','tuseday','wednesday','thursday','friday','saturday']
const today = new Date()
const yy = today.getFullYear()
const mm = today.getMonth()
const dt = today.getDate()
const dy = today.getDay()

function render (){
    getElemt('.header p').innerHTML = `${yy}`
    getElemt('.month').innerHTML = `
        <p>${mm + 1}</p>
        <p>${months[mm].substring(0, 3)}</p>` // 取出前三個字元
    getElemt('.date').innerHTML = `${dt}`
    getElemt('.fullMonth .title').innerHTML = `${months[mm]}`
    getElemt('.week .day').innerHTML = `星期${days[dy]}`
    getElemt('.week .en').innerHTML = `${en[dy]}`
}

```

### 電子鐘
```javascript=
function timer (){
    let newTime = new Date()
    let h = newTime.getHours()
    let m = newTime.getMinutes()
    let s = newTime.getSeconds()
    let hour = ((h < 10) ? '0' : '') + h
    let min = ((m < 10) ? '0' : '') + m
    let sec = ((s < 10) ? '0' : '') + s

    getElemt('.timer').innerHTML = `${hour}:${min}:${sec}`
}
setInterval(timer, 1000)
```

## 六、製作小月曆
### 取得當月份總天數
* 當月的第32天 - 當天日期 = 當月最後一天
* 舉栗：8月的第32天為9/1，32-1=31
* 得到8月的最後一天為31號，當月有31天
```javascript=
function daysInMonth(m, y) {
    return 32 - new Date(y, m, 32).getDate()
}
```
### 小月曆本人
參考資料：[Challenge of building a Calendar with Pure JavaScript](https://link.medium.com/1UTiIVbCP8)
```javascript=
function calendar (year, month){
    let firstDay = (new Date(year, month)).getDay()
    // 取得當月第一天
    let date = 1
    // 當月第一天/日期，起始值
    for( let r=0; r<6; r++ ) { // 最多6行
        let row = createElemt('tr')
        let cell, cellText

        for ( let i=0; i<7; i++) {
            // 一星期7天，最多7列
            if( r === 0 && i < firstDay ) {
                // 第0列，且當週 < 7天，填補空格
                cell = createElemt('td')
                row.appendChild(cell)

            } else if ( date > daysInMonth(month, year) ) {
                // 若當天日期 > 當月最後一天，跳出現在迴圈
                break

            } else {
                cell = createElemt('td')
                cellText = document.createTextNode(date)
                // 補上空格並填入日期

                if( year === yy && month === mm && date === dt ) {
                    cell.classList.add('now')
                    // 今天日期加上 now
                }
                cell.appendChild(cellText)
                row.appendChild(cell)
                date ++
            }
        }
        getElemt('.fullMonth table').appendChild(row)
    } 
}
```

### 農曆計算
參考資料：[1900年至2100年公历、农历互转Js代码](https://blog.jjonline.cn/userInterFace/173.html)

## 七、關燈效果
![](https://i.imgur.com/EDIaxAp.png =x420)![](https://i.imgur.com/XGvytrh.png =x420)

運用 `text-shadow` 的堆疊方式就可以做出文字發光效果
開關的部分我用 `checkbox` 和 `label` 做簡單的切換
* HTML
```htmlmixed=
<div class="lightBtn">
    <input id="btn" type="checkbox"/>
    <label for="btn">
        <span class="off">關燈</span>
        <span class="on">開燈</span>
    </label>
</div>
```
* SASS
```sass=
#btn
    display: none
    // 隱藏 checkbox
#btn:checked ~ label 
    // 點選 checkbox 後，變更 label 內設定
    .off
    // 關燈樣式 ON
    .on
    // 開燈樣式 OFF
```
* JavaScript
```javascript=
const btn = getElemt('#btn')
    btn.addEventListener('click', () => {
    if( btn.checked ) {
        getElemt('body').classList.add('active')
    } else {
        getElemt('body').classList.remove('active')
    }
})
```

---
DEMO：[Calendar 五金行日曆](https://codepen.io/ericadu/full/GRZJjjE)