前端開發規範

李一楓發表於2020-01-13

一般規範

命名規範

命名分類

  • camelCase(駝峰式,也叫小駝峰命名,e.g. userInfo
  • PascalCase(帕斯卡命名式,也叫大駝峰命名,e.g. UserInfo
  • kebab-case(短橫線連線式,e.g. user-info
  • snake_case(下劃線連線式,e.g. user_info

變數命名

  • 命名方式 : 小駝峰式命名方法
  • 命名規範 : 型別+物件描述或屬性的方式
// bad
var getTitle = "LoginTable"

// good
let tableTitle = "LoginTable"
複製程式碼

函式命名

  • 命名方式 : 小駝峰方式 ( 建構函式使用大駝峰命名法 )
  • 命名規則 : 字首為動詞
動詞    含義	                        返回值
can	判斷是否可執行某個動作 (權 )	函式返回一個布林值。true:可執行;false:不可執行
has	判斷是否含有某個值	        函式返回一個布林值。true:含有此值;false:不含有此值
is	判斷是否為某個值	                函式返回一個布林值。true:為某個值;false:不為某個值
get	獲取某個值                  	函式返回一個非布林值
set	設定某個值	                無返回值、返回是否設定成功或者返回鏈式物件
複製程式碼

推薦:

//是否可閱讀
function canRead(){
    return true;
}

//獲取姓名
function getName{
    return this.name
}
複製程式碼

常量命名

  • 命名方法 : 全部大寫
  • 命名規範 : 使用大寫字母和下劃線來組合命名,下劃線用以分割單詞。

推薦:

const MAX_COUNT = 10;
const URL = 'http://test.host.com';
複製程式碼

類的成員命名

  • 公共屬性和方法 : 同變數命名方式
  • 私有屬性和方法 : 字首為下劃線(_)後面跟公共屬性和方法一樣的命名方式

推薦:

function Student(name) {
    var _name = name; // 私有成員
 
    // 公共方法
    this.getName = function () {
        return _name;
    }
 
    // 公共方式
    this.setName = function (value) {
        _name = value;
    }
}
var st = new Student('tom');
st.setName('jerry');
console.log(st.getName()); // => jerry:輸出_name私有變數的值
複製程式碼

註釋規範

單行註釋

  1. 單獨一行://(雙斜線)與註釋文字之間保留一個空格
  2. 在程式碼後面新增註釋://(雙斜線)與程式碼之間保留一個空格,並且//(雙斜線)與註釋文字之間保留一個空格。
  3. 註釋程式碼://(雙斜線)與程式碼之間保留一個空格。

推薦 :

// 呼叫了一個函式 <= 1)單獨在一行
setTitle();
 
var maxCount = 10; // 設定最大量 <= 2)在程式碼後面註釋
 
// setName(); // <= 3)註釋程式碼
複製程式碼

多行註釋 ( / 註釋說明 / )

  • 若開始(/\*)和結束(\*/)都在一行,推薦採用單行註釋
  • 若至少三行註釋時,第一行為/\*,最後行為\*/,其他行以*開始,並且註釋文字與*保留一個空格。

推薦 :

/*
* 程式碼執行到這裡後會呼叫setTitle()函式
* setTitle():設定title的值
*/
setTitle();
複製程式碼

函式 ( 方法 ) 註釋

函式(方法)註釋也是多行註釋的一種,但是包含了特殊的註釋要求,參照JavaDoc規範

語法:

/** 
* 函式說明 
* @關鍵字 
*/
複製程式碼

常用註釋關鍵字:

註釋名 語法 含義 示例
@param @param 引數名 {引數型別} 描述資訊 描述引數的資訊 @param name {String} 傳入名稱
@return @return {返回型別} 描述資訊 描述返回值的資訊 @return {Boolean} true:可執行;false:不可執行
@author @author 作者資訊 [附屬資訊:如郵箱、日期] 描述此函式作者的資訊 @author 張三 2015/07/21
@version @version XX.XX.XX 描述此函式的版本號 @version 1.0.3
@example @example 示例程式碼 @example setTitle('測試')

需要新增註釋的地方

程式碼註釋在一個專案的後期維護中顯的尤為重要,所以我們要為每一個被複用的元件編寫元件使用說明,為元件中每一個方法編寫方法說明。

以下情況,務必新增註釋:

1. 公共元件使用說明
2. 各元件中重要函式或者類說明
3. 複雜的業務邏輯處理說明
4. 特殊情況的程式碼處理說明,對於程式碼中特殊用途的變數、存在臨界值、函式中使用的hack、使用了某種演算法或思路等需要進行註釋描述
7. 多重 if 判斷語句
複製程式碼

Vue規範

Vue專案規範

結構化規範(webpack)

   ├── index.html                      入口頁面
   ├── favicon.ico                     頁面圖示
   ├── .babelrc                        babel規則
   ├── .editorconfig                   編輯器配置
   ├── .eslintignore                   eslint忽略規律
   ├── .eslintrc.js                    eslint規則
   ├── .gitignore                      git忽略規則
   ├── build                           構建指令碼目錄
   │   ├── build-server.js                 執行本地構建伺服器,可以訪問構後的頁面
   │   ├── build.js                        生產環境構建指令碼
   │   ├── dev-client.js                   開發伺服器熱過載指令碼,主要用來實現開發階段的頁面自動重新整理
   │   ├── dev-server.js                   執行本地開發伺服器
   │   ├── utils.js                        構建相關工具方法
   │   ├── webpack.base.conf.js            wabpack基礎配置
   │   ├── webpack.dev.conf.js             wabpack開發環境配置
   │   └── webpack.prod.conf.js            wabpack生產環境配置
   │   └── webpack.cdn.conf.js             wabpack cdn配置
   │   └── webpack.dll.conf.js             wabpack dll配置
   ├── config                          專案配置
   │   ├── dev.env.js                      開發環境變數
   │   ├── index.js                        專案配置檔案
   │   ├── prod.env.js                     生產環境變數
   │   └── test.env.js                     測試環境變數
   ├── mock                            mock資料目錄
   │   └── hello.js
   ├── package.json                    npm包配置檔案,裡面定義了專案的npm指令碼,依賴包等資訊
   ├── readmd.md                       專案描述檔案
   ├── src                                專案原始碼目錄
   │   ├── main.js                            入口js檔案
   │   ├── App.vue                            根元件
   │   ├── components                         公共元件目錄
   │   │   └── ComponentItem.vue
   │   ├── assets                         靜態資源目錄,這裡的資源會被wabpack構建
   │   │   ├── css                            公共樣式檔案目錄
   │   │   ├── js                             公共js檔案目錄(如幫助方法)
   │   │   └── img                            圖片存放目錄
   |   |── lib                            外部引用的外掛存放及修改檔案
   |   |—— datas                          模擬資料,臨時存放
   │   ├── routes                         前端路由
   │   │   └── index.js
   │   ├── apis                           介面,統一管理
   │   │   └── index.js
   │   ├── store                          vuex, 統一管理
   │   │   └── index.js
   │   └── views                          檢視模組名
   │       ├── view-module                檢視模組
   |            └── index.vue             檢視模組的主頁面
   │       ├── hello.vue
   │       └── notfound.vue
   ├── static                             純靜態資源,不會被wabpack構建。
   └── test                               測試檔案目錄(unit&e2e)
       └── unit                               單元測試
           ├── index.js                           入口指令碼
           ├── karma.conf.js                      karma配置檔案
           └── specs                           單測case目錄
               └── Hello.spec.js
複製程式碼

目錄、檔案、元件命名規範

1. 目錄

目錄統一使用kebab-case風格

2. views下的檔案

  • js類檔案使用PascalCase,如UserInfo.js
  • 其他資原始檔統一使用kebab-case風格,如user-detail.js, user-detail.css, user-avatar.png

3. 元件檔案

  • 命名遵循PascalCase約定。

元件檔名除index.vue之外,一律採用PascalCase(大駝峰)寫法。原因是引入元件時,元件的變數通常用PascalCase格式,以區別於一般變數。元件檔名與變數名一致,方便對應。

import UserBook from './user/UserBook'
複製程式碼
  • 元件名應該始終是多個單詞的,根元件 App 除外

html元素都是單個單詞的(如<article>,<header>),為了區分元件和一般html元素,元件由多個單片語成,如BookItem.vue,單獨的Book.vue不推薦。

  • 元件使用遵循kebab-case 約定

在頁面中使用元件需要前後閉合,並以短線分隔,如:

<user-book></user-book>
複製程式碼

Vue開發規範

Vue檔案結構

  • 基本結構

順序:template -> script -> style。一個元件儘量不要超過200行,頁面包含獨立部分時儘量分離成子元件。

<template>
  <div>...</div>
</template>
<script>
  export default {
    components: {},
    data() {
      return {};
    },
    created(){},
    methods: {},
  };
</script>
<!-- 宣告語言,並且新增scoped -->
<style lang="scss" scoped>...</style>
複製程式碼
  • 元件/例項的選項順序
- name          (全域性引用)
- components    (模板依賴)
- directives    ...
- filters       ...
- mixins        (組合)
- props         (介面)
- data          (本地狀態屬性)
- computed      ...
- watch         (響應回撥)
- created       (生命週期函式)
- mounted       ...
- methods       (例項屬性)
複製程式碼

Vue Router Path規範

router path採用kebab-case格式。

用下劃線(如:/user_info)或camelCase(如:/userInfo)的單詞被當成一個單詞,搜尋引擎無法區分語義。

// bad
{
    path: '/user_info', // user_info當成一個單詞
    name: 'UserInfo',
    component: UserInfo,
    meta: {
    title: ' - 使用者',
    desc: ''
    }
},

// good
{
    path: '/user-info', // 能解析成user info
    name: 'UserInfo',
    component: UserInfo,
    meta: {
    title: ' - 使用者',
    desc: ''
    }
},
複製程式碼

元件開發規範

1. 註冊元件

註冊元件的時候,全部使用 PascalCase 格式。

import UserBook from './user/UserBook'
複製程式碼

2. props 命名規範

  • 在宣告prop的時候,其命名應該始終使用camelCase,而在模板中應該始終使用kebab-case
<!-- bad -->
<welcome-message greetingText="hi"></welcome-message>

<script>
  props: {
    'greeting-text': String
  }
</script>

<!-- good -->
<welcome-message greeting-text="hi"></welcome-message>

<script>
  props: {
    greetingText: String;
  }
</script>
複製程式碼
  • prop定義應該儘量詳細
    • 元件 props 原子化
    • 提供預設值
    • 使用 type 屬性校驗型別
// bad 這樣做只有開發原型系統時可以接受
props: ['status']

// good
props: {
  status: {
    type: String,
    required: true,
    validator: function (value) {
      return [
        'syncing',
        'synced',
        'version-conflict',
        'error'
      ].indexOf(value) !== -1
    }
  }
}
複製程式碼

3. methods 命名規範

  • 駝峰式命名,統一使用動詞或者動詞+名詞形式
//bad
go、nextPage、show、login、get_code

// good
jumpPage、openCarInfoDialog
複製程式碼
  • 請求資料方法,以 data 結尾
//bad
takeData、confirmData、getList、postForm

// good
getListData、postFormData
複製程式碼
  • 儘量使用常用單詞開頭(set、get、go、can、has、is)

附: 函式方法常用的動詞:

get 獲取/set 設定,
add 增加/remove 刪除
create 建立/destory 移除
start 啟動/stop 停止
open 開啟/close 關閉,
read 讀取/write 寫入
load 載入/save 儲存,
create 建立/destroy 銷燬
begin 開始/end 結束,
backup 備份/restore 恢復
import 匯入/export 匯出,
split 分割/merge 合併
inject 注入/extract 提取,
attach 附著/detach 脫離
bind 繫結/separate 分離,
view 檢視/browse 瀏覽
edit 編輯/modify 修改,
select 選取/mark 標記
copy 複製/paste 貼上,
undo 撤銷/redo 重做
insert 插入/delete 移除,
add 加入/append 新增
clean 清理/clear 清除,
index 索引/sort 排序
find 查詢/search 搜尋,
increase 增加/decrease 減少
play 播放/pause 暫停,
launch 啟動/run 執行
compile 編譯/execute 執行,
debug 除錯/trace 跟蹤
observe 觀察/listen 監聽,
build 構建/publish 釋出
input 輸入/output 輸出,
encode 編碼/decode 解碼
encrypt 加密/decrypt 解密,
compress 壓縮/decompress 解壓縮
pack 打包/unpack 解包,
parse 解析/emit 生成
connect 連線/disconnect 斷開,
send 傳送/receive 接收
download 下載/upload 上傳,
refresh 重新整理/synchronize 同步
update 更新/revert 復原,
lock 鎖定/unlock 解鎖
check out 簽出/check in 簽入,
submit 提交/commit 交付
push 推/pull 拉,
expand 展開/collapse 摺疊
begin 起始/end 結束,
start 開始/finish 完成
enter 進入/exit 退出,
abort 放棄/quit 離開
obsolete 廢棄/depreciate 廢舊,
collect 收集/aggregate 聚集
複製程式碼

4. 多個屬性的html元素規範

多個特性的元素,佔據一行過長時,應該分多行撰寫,每個特性一行。(增強更易讀)

<!-- bad -->
<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
<my-component foo="fooattribute" bar="barattribute" baz="bazattribute"></my-component>

<!-- good -->
<img
  src="https://vuejs.org/images/logo.png"
  alt="Vue Logo"
>
<my-component
  foo="fooattribute"
  bar="barattribute"
  baz="bazattribute"
>
</my-component>
複製程式碼

5. 元素屬性的順序

原生屬性放前面,指令放後面

  - class
  - id,ref
  - name
  - data-*
  - src, for, type, href,value,max-length,max,min,pattern
  - title, alt,placeholder
  - aria-*, role
  - required,readonly,disabled
  - is
  - v-for
  - key
  - v-if
  - v-else-if
  - v-else
  - v-show
  - v-cloak
  - v-pre
  - v-once
  - v-model
  - v-bind,:
  - v-on,@
  - v-html
  - v-text
複製程式碼

6. 指令規範

  • 指令有縮寫則一律採用縮寫形式
// bad
v-bind:code="code"
v-on:click="getUserData"

// good
:code="code"
@click="getUserData"
複製程式碼
  • v-for 迴圈必須加上 key 屬性,在整個 for 迴圈中 key 需要唯一
<!-- bad -->
<ul>
    <li v-for="todo in todos">
      {{ todo.text }}
    </li>
</ul>

<!-- good -->
<ul>
    <li v-for="todo in todos" :key="todo.id">
      {{ todo.text }}
    </li>
</ul>
複製程式碼
  • 避免 v-if 和 v-for 同時用在一個元素上(效能問題)

    出現這樣的需求,有兩種解決方案:

    1. 將資料替換為一個計算屬性,讓其返回過濾後的列表

            <!-- bad -->
        <ul>
          <li v-for="user in users" v-if="user.isActive" :key="user.id">
            {{ user.name }}
          </li>
        </ul>
      
        <!-- good -->
        <ul>
          <li v-for="user in activeUsers" :key="user.id">
            {{ user.name }}
          </li>
        </ul>
      
        <script>
        computed: {
          activeUsers: function () {
            return this.users.filter(function (user) {
              return user.isActive
            })
          }
        }
        </script>
      複製程式碼
    2. 將 v-if 移動至容器元素上 (比如 ul, ol)

        <!-- bad -->
        <ul>
          <li v-for="user in users" v-if="shouldShowUsers" :key="user.id">
            {{ user.name }}
          </li>
        </ul>
      
        <!-- good -->
        <ul v-if="shouldShowUsers">
          <li v-for="user in users" :key="user.id">
            {{ user.name }}
          </li>
        </ul>
      複製程式碼

其他

  1. 避免 this.$parent
  2. 除錯資訊 console.log() 使用完及時刪除
  3. 除了三目運算,if,else 等禁止簡寫
  4. 行尾分號可以加或不加,應統一風格,但建議都不加。分號的作用在現代ES指令碼不會影響,如果你不懂分號的作用,該入的坑照樣會入,沒有分號的程式碼更加清爽。大部分Vue專案都去除了分號。
    // bad
    if (true)
      alert(name);
    console.log(name);
    
    // bad
    if (true)
    alert(name);
    console.log(name);
    
    // good
    if (true) {
      alert(name)
    }
    console.log(name)
    複製程式碼

HTML規範

指令碼載入

  • 相容老舊瀏覽器(IE9-)時:

指令碼引用寫在 body 結束標籤之前,並帶上 async 屬性。這雖然在老舊瀏覽器中不會非同步載入指令碼,但它只阻塞了 body 結束標籤之前的 DOM 解析,這就大大降低了其阻塞影響。

  • 而在現代瀏覽器中:

指令碼將在 DOM 解析器發現 body 尾部的 script 標籤才進行載入,此時載入屬於非同步載入,不會阻塞 CSSOM(但其執行仍發生在 CSSOM 之後)。

因此,相容所有瀏覽器,則推薦:

<html>
  <head>
    <link rel="stylesheet" href="main.css">
  </head>
  <body>
    <!-- body goes here -->
 
    <script src="main.js" async></script>
  </body>
</html>
複製程式碼

只相容現代瀏覽器,則推薦:

<html>
  <head>
    <link rel="stylesheet" href="main.css">
    <script src="main.js" async></script>
  </head>
  <body>
    <!-- body goes here -->
  </body>
</html>
複製程式碼

語義化

語義化是指:根據元素其被創造出來時的初始意義來使用它。 用正確的標籤表達正確的內容,這也有利於SEO。

正確合理使用nav, header, article, section 等語義標籤,不要全篇div。

alt標籤不為空

<img> 標籤的 alt 屬性指定了替代文字,用於在影像無法顯示或者使用者禁用影像顯示時,代替影像顯示在瀏覽器中的內容。 假設由於下列原因使用者無法檢視影像,alt 屬性可以為影像提供替代的資訊:

  • 網速太慢
  • src 屬性中的錯誤
  • 瀏覽器禁用影像
  • 使用者使用的是螢幕閱讀器

從SEO角度考慮,瀏覽器的爬蟲爬不到圖片的內容,所以我們要有文字告訴爬蟲圖片的內容

結構、表現、行為三者分離

  • 儘量在文件和模板中只包含結構性的 HTML;
  • 將所有表現程式碼,移入樣式表中;
  • 將所有動作行為,移入指令碼之中。

HTML只關注內容

  • HTML只顯示展示內容資訊
  • 不要引入一些特定的 HTML 結構來解決一些視覺設計問題,多考慮使用偽元素:before:after
  • 不要將 img 元素當做專門用來做視覺設計的元素
  • 樣式上的問題應該使用css解決
<!-- bad -->
<!-- We should not introduce an additional element just to solve a design problem  -->
<span class="text-box">
  <span class="square"></span>
  See the square next to me?
</span>
css 程式碼:
.text-box > .square {
  display: inline-block;
  width: 1rem;
  height: 1rem;
  background-color: red;
}

<!-- good -->
<!-- That's clean markup! -->
<span class="text-box">
  See the square next to me?
</span>
css 程式碼:
/* We use a :before pseudo element to solve the design problem of placing a colored square in front of the text content */
.text-box:before {
  content: "";
  display: inline-block;
  width: 1rem;
  height: 1rem;
  background-color: red;
}
複製程式碼

JS規範

一般規範

使用嚴格等===

總是使用 === 精確的比較操作符,避免在判斷的過程中,由 JavaScript 的強制型別轉換所造成的困擾。

this關鍵字

只在物件構造器、方法和在設定的閉包中使用 this 關鍵字。

this 的語義常容易被誤導。它時而指向全域性物件(大多數時),時而指向呼叫者的定義域(在 eval 中),時而指向 DOM 樹中的某一節點(當用事件處理繫結到 HTML 屬性上時),時而指向一個新建立的物件(在構造器中),還時而指向其它的一些物件(如果函式被 call() 和 apply() 執行和呼叫時)。

正因為它是如此容易地被搞錯,請限制它的使用場景:

  • 在建構函式中
  • 在物件的方法中(包括由此建立出的閉包內)

三元操作符

用三元操作符分配或返回語句。在比較簡單的情況下使用,避免在複雜的情況下使用。

// bad
if(x === 10) {
  return 'valid';
} else {
  return 'invalid';
}

// good
return x === 10 ? 'valid' : 'invalid'
複製程式碼

不使用eval()函式

就如eval的字面意思來說,惡魔,使用eval()函式會帶來安全隱患。 eval()函式的作用是返回任意字串,當作js程式碼來處理。

使用ES6編碼規範

  • 定義變數使用let ,定義常量使用const
  • 靜態字串一律使用單引號或反引號,動態字串使用反引號
    // bad
    const a = 'foobar';
    const b = 'foo' + a + 'bar';
    
    // good
    const a = 'foobar';
    const b = `foo${a}bar`;
    const c = 'foobar';
    
    複製程式碼
  • 解構賦值
    // 1. 陣列解構賦值
    const arr = [1, 2, 3, 4];
    // bad
    const first = arr[0];
    const second = arr[1];
    // good
    const [first, second] = arr;
    
    // 2. 物件解構賦值
    // bad
    function getFullName(user) {
      const firstName = user.firstName;
      const lastName = user.lastName;
    }
    // good
    function getFullName(obj) {
      const { firstName, lastName } = obj;
    }
    // best
    function getFullName({ firstName, lastName }) {}
    複製程式碼
  • 使用擴充套件運算子(...)拷貝陣列。
    const items = [1, 2, 3, 4, 5];
    // bad
    const itemsCopy = items;
    // good
    const itemsCopy = [...items];
    複製程式碼
  • 箭頭函式 需要使用函式表示式的場合,儘量用箭頭函式代替。因為這樣更簡潔,而且繫結了 this
    // bad
    const self = this;
    const boundMethod = function(...params) {
      return method.apply(self, params);
    };
    // good
    const boundMethod = (...params) => method.apply(this, params);
    複製程式碼

CSS規範

合理地使用ID

一般情況下ID不應該被用於樣式,並且ID的權重很高,所以不使用ID解決樣式的問題,而是使用class

css選擇器中避免使用標籤名

從結構、表現、行為分離的原則來看,應該儘量避免css中出現HTML標籤,並且在css選擇器中出現標籤名會存在潛在的問題。

使用直接子選擇器

使用後代選擇器常可能導致設計問題和效能損耗,這是個不好的做法,應總是考慮直接子選擇器

/* bad */
.content .title {
  font-size: 2rem;
}
/* good */
.content > .title {
  font-size: 2rem;
}
複製程式碼

儘量使用縮寫屬性

儘量使用縮寫屬性對於程式碼效率和可讀性是很有用的,比如font屬性。

/* bad */
.user-box {
    border-top-style: none;
    font-family: palatino, georgia, serif;
    font-size: 100%;
    line-height: 1.6;
    padding-bottom: 2em;
    padding-left: 1em;
    padding-right: 1em;
    padding-top: 0;
}

/* good */
.user-box {
   border-top: 0;
   font: 100%/1.6 palatino, georgia, serif;
   padding: 0 1em 2em; 
}
複製程式碼

0後面不帶單位

/* bad */
.user-box {
    padding-bottom: 0px;
    margin: 0em;
}

/* good */
.user-box {
    padding-bottom: 0;
    margin: 0;
}
複製程式碼

屬性格式

  • 為了保證一致性和可擴充套件性,每個宣告應該用分號結束,每個宣告換行。
  • 屬性名的冒號後使用一個空格。出於一致性的原因,
  • 屬性和值(但屬性和冒號之間沒有空格)的之間始終使用一個空格。
  • 每個選擇器和屬性宣告總是使用新的一行。
  • 屬性選擇器或屬性值用雙引號(""),而不是單引號('')括起來。

屬性順序

作為最佳實踐,按照分組及重要性進行排序。具體地,按照由外向內,從元素與外界的關係,是否會影響外部佈局,到外邊距,內邊距等。

  1. 佈局相關(display, position, float, overflow, clear),因為元素的佈局會對對相鄰元素產生影響,自身甚至會脫離原來的文件流,所以比較重要。
  2. 盒模型相關(width, height, margin, padding)
  3. 外觀 (color, background, border, box-shadow)
  4. 文字排版 (font-size, font-family, text-align, text-transform)
  5. 其他 (cursor, z-index)
/* bad */
 .box {
  font-family: 'Arial', sans-serif;
  border: 3px solid #ddd;
  left: 30%;
  position: absolute;
  text-transform: uppercase;
  background-color: #eee;
  right: 30%;
  isplay: block;
  font-size: 1.5rem;
  overflow: hidden;
  padding: 1em;
  margin: 1em;
}

/* good */
.box {
  display: block;
  position: absolute;
  left: 30%;
  right: 30%;
  overflow: hidden;
  
  margin: 1em;
  padding: 1em;
  
  background-color: #eee;
  border: 3px solid #ddd;
  font-family: 'Arial', sans-serif;
  font-size: 1.5rem;
  text-transform: uppercase;
}
複製程式碼

相關文章