初心者がCSSフレームワークを自作してみた

# はじめに
この記事は [金沢工業大学 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/kit-calendar) 7日目の記事です．

https://qiita.com/advent-calendar/2023/kit-calendar


# そもそもCSSフレームワークって？
CSSフレームワークというのは簡単に言うと「Webサイト構築で使えるパーツ集」みたいなものです．
ボタン・コンテナ・メニュー・カラムなどの様々なパーツがひとまとめになっていて，CSSで長々とコードを書かなくても簡単に美しいデザインのWebサイトを作ることができるというものです．

代表的なものだと
* [Bootstrap](https://getbootstrap.com/)
* [Tailwind CSS](https://tailwindcss.com/)
* [Primer CSS](https://primer.style/css/storybook/)

などがありますね．


# なぜフレームワークを自作したのか
世の中にはBootstrapをはじめとした素晴らしいCSSフレームワークが大量にあるのに，なぜ今さら自作しようと思ったのでしょうか？

答えは簡単　<B>自分の好きなデザインで作れるから</B>　です．

BootstrapやTailwindは確かに素晴らしいCSSフレームワークです．でもやっぱり自分の好きなデザインで楽にWebサイトを作りたい...ということで今回CSSフレームワークの自作へと至りました．(一応CSSの勉強にもなるから...）



# 注意
:::note warn
この記事はCSSを学び始めて1年ちょっとの初心者が書いています．
拙いコードや内容の誤り等あるかと思いますが，もし何かあればご指摘いただけますと幸いです．
:::


# 制作物の概要
今回はこんな感じのCSSフレームワークを目指しました．

* ボタン・コンテナ・メニュー等のコンポーネントを備えた汎用フレームワーク
* グローバルメニュー・カラムレイアウトを簡単に実現できるように
* オレンジを基調とした明るい色使い
* 丸ゴシックや角丸を多用した親しみやすいデザイン


# サンプルページ
今回作ったCSSフレームワークのサンプルページがこちらになります．

https://zawataku.github.io/zawataku_framework/

レスポンシブ非対応な部分があったり，対応していないHTML要素があったりとまだ不完全ですが...

# 解説
それではここから，実装した各部分について簡単な解説をしていこうと思います．

### 開発環境
* Windows 11 Pro 22H2
* Microsoft Visual Studio Code v.1.84.2
```powershell
$ ver
Microsoft Windows [Version 10.0.22621.2715]

$ code -v
1.84.2
1a5daa3a0231a0fbba4f14db7ec463cf99d7768e
x64
```

### フォント
主にフォントについて記述していきます．
```CSS
/***********************************
*	fonts	*
***********************************/
@font-face {
    font-family: 'Rounded M Plus 1c Regular';
    src: url(../fonts/MPLUSRounded1c-Regular.ttf) format(truetype);
}

@font-face {
    font-family: 'Rounded M Plus 1c Bold';
    src: url(../fonts/MPLUSRounded1c-Bold.ttf) format(truetype);
}

* {
    margin: 0;
    padding: 0;
    color: #333333;
    font-family: 'Rounded M Plus 1c Regular';
    transform: rotateZ(0.03deg)/*フォントの乱れを修正*/;
}

b,
strong {
    font-family: 'Rounded M Plus 1c Bold';
}
```
フォントは今回個人的に好きな丸ゴシックのフリーフォントである[M PLUS Rounded 1c](https://fonts.google.com/specimen/M+PLUS+Rounded+1c)をチョイス．
見出し用の「Bold」と本文用の「Regular」，2種類の太さを用意しました．

このM PLUS Rounded 1c，非常に美しいフォントで気に入っているのですが，20px以下で表示すると何故か文字がジャギる（文字のふちがギザギザになる）という現象が発生します．
そこで[こちら](https://tips.back2nature.jp/css/m-plus-rounded-1c-is-dirty-but-it-is-displayed-neatly-by-adding-css/)のサイトを参考に
```CSS
transform: rotateZ(0.03deg);
```
を追記し，ジャギーを抑えています．

### Wrap・Width
特筆することはないです．
Widthを簡単に指定できるようにしてみました．
```CSS
/***********************************
*	Wrap	*
***********************************/
.wrap {
    margin: auto;
    overflow: hidden;
}


/***********************************
*	Width	*
***********************************/
.w-800 {
    width: 800px;
}

.w-900 {
    width: 900px;
}

.w-1000 {
    width: 1000px;
}

.w-1100 {
    width: 1100px;
}

.w-1200 {
    width: 1200px;
}

.w-20-pct {
    width: 20%;
}

.w-30-pct {
    width: 30%;
}

.w-50-pct {
    width: 50%;
}

.w-75-pct {
    width: 75%;
}

.w-100-pct {
    width: 100%;
}
```
### Border
見出しのアクセント等に使える太めのBorderです．
```CSS
/***********************************
*	Border	*
***********************************/
.border-top {
    border-top: solid 5px #FF5722;
}

.border-right {
    border-right: solid 5px #FF5722;
}

.border-bottom {
    border-bottom: solid 5px #FF5722;
}

.border-left {
    border-left: solid 5px #FF5722;
}
```

### 見出し
コンテンツの見出しです．h1～h6まであります．
フォント太めの「Bold」を採用．
```CSS
/***********************************
*	HeadLine	*
***********************************/
h1,
h2,
h3,
h4,
h5,
h6 {
    margin-top: 40px;
    margin-bottom: 10px;
    padding: 0 5px 0 5px;
    font-family: 'Rounded M Plus 1c Bold';
}

h1 {
    font-size: 30px;
}

h2 {
    font-size: 26px;
}

h3 {
    font-size: 22px;
}

h4 {
    font-size: 18px;
}

h5 {
    font-size: 14px;
}

h6 {
    font-size: 12px;
}
```

### Input
個人的に一番頑張ったところです．
```CSS
/***********************************
*	Input	*
***********************************/
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="serch"],
input[type="tel"],
input[type="date"],
input[type="week"],
input[type="time"] {
    margin: 5px 0 5px 0;
    padding: 10px 15px;
    font-size: 16px;
    border-radius: 25px;
    border: 2px solid #ddd;
    box-sizing: border-box;
}
```
まずは入力フォーム関連のレイアウトです．
```CSS
border-radius: 25px;
```
でフォームの角を大きく丸めています．
参考にしたデザインはこちら．Googleの検索フォームです．
![スクリーンショット 2023-12-04 235925.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619955/418d2a5b-c137-82b3-ddf7-fd00926e0183.png)

次に入力フォームにフォーカスが当たった状態のデザインを作っていきます．
```CSS
input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
input[type="serch"]:focus,
input[type="tel"]:focus,
input[type="date"]:focus,
input[type="week"]:focus,
input[type="time"]:focus {
    border: 2px solid #FFAB91;
    transition: all 0.5s ease 0s;
    z-index: 10;
    outline: 0;
}
```
ここでのポイントは
```CSS
border: 2px solid #FFAB91;
transition: all 0.5s ease 0s;
```
の二か所です．
入力フォームにフォーカスが当たると「ふわっ」って感じで2pxのborderが付くようになっています．

次は「送信」などのボタン関連です．
```CSS
input[type="button"]:hover,
input[type="submit"]:hover,
input[type="reset"]:hover {
    background-color: #FF5722;
    color: #FFF;
    transition: all 1s ease 0s;
}

button {
    margin: 5px 0 5px 0;
    padding: 10px 15px;
    font-size: 16px;
    border-radius: 25px;
    border: 2px solid #FF5722;
    background-color: #FFF;
    box-sizing: border-box;
    color: #FF5722;
    cursor: pointer;
}

button:hover {
    background-color: #FF5722;
    color: #FFF;
    transition: all 1s ease 0s;
}
```
基本的にはさっきの入力フォームと似たようなつくりです．マウスカーソルが上に乗ると「ふわっ」と色が変わります．

最後はInput要素最難関だったcheckboxとradioです．
まずはHTMLがこちら．
```HTML
<p>
    <input type="radio" id="radio" value="ラジオボタン">
    <label for="radio" class="radio">ラジオボタン</label>
</p> <!--ラジオボタンはlabelをつけること-->
        
<p>
    <input type="checkbox" id="checkbox" value="チェックボックス">
    <label for="checkbox" class="checkbox">チェックボックス</label>
</p> <!--チェックボックスはlabelをつけること-->
```
↑checkboxとradioだけはどうしてもデフォルトのHTML要素をカスタマイズできなかったので，label要素をくっつけて対応しました．
```CSS
input[type=radio],
input[type=checkbox] {
    display: none;
}
```
↑続いて，デフォルトのボタンを消して...
```CSS
.radio,
.checkbox {
    box-sizing: border-box;
    transition: background-color 0.2s linear;
    position: relative;
    display: inline-block;
    margin: 5px 0 5px 0;
    padding: 12px 12px 12px 42px;
    border-radius: 25px;
    background-color: #f6f7f8;
    vertical-align: middle;
    cursor: pointer;
}

.radio:hover,
.checkbox:hover {
    background-color: #FBE9E7;
}

.radio:hover:after,
.checkbox:hover:after {
    border-color: #FF5722;
}

.radio:after,
.checkbox:after {
    transition: border-color 0.2s linear;
    position: absolute;
    top: 50%;
    left: 15px;
    display: block;
    margin-top: -10px;
    width: 16px;
    height: 16px;
    border: 2px solid #bbb;
    border-radius: 6px;
    content: '';
}

.radio:before {
    transition: opacity 0.2s linear;
    position: absolute;
    top: 50%;
    left: 20px;
    display: block;
    margin-top: -5px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background-color: #FF5722;
    content: '';
    opacity: 0;
}

input[type=radio]:checked+.radio:before {
    opacity: 1;
}

.checkbox:before {
    transition: opacity 0.2s linear;
    position: absolute;
    top: 50%;
    left: 21px;
    display: block;
    margin-top: -7px;
    width: 5px;
    height: 9px;
    border-right: 3px solid #FF5722;
    border-bottom: 3px solid #FF5722;
    content: '';
    opacity: 0;
    transform: rotate(45deg);
}

input[type=checkbox]:checked+.checkbox:before {
    opacity: 1;
}
```
デザインを良い感じに調整して完成です．

![スクリーンショット 2023-12-06 105222.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619955/337052f9-0352-0575-a174-e37e2df69766.png)

### グローバルメニュー
簡単なグローバルメニューも作ってみました．
まずHTMLがこちら．
```HTML
<div class="global-menu"><!-- メニュー項目3つ -->
    <div class="menu-item-3">MENU 1</div>
    <div class="menu-item-3">MENU 2</div>
    <div class="menu-item-3">MENU 3</div>
</div>
        
<div class="global-menu"><!-- メニュー項目4つ -->
    <div class="menu-item-4">MENU 1</div>
    <div class="menu-item-4">MENU 2</div>
    <div class="menu-item-4">MENU 3</div>
    <div class="menu-item-4">MENU 4</div>
</div>
        
<div class="global-menu"><!-- メニュー項目5つ -->
    <div class="menu-item-5">MENU 1</div>
    <div class="menu-item-5">MENU 2</div>
    <div class="menu-item-5">MENU 3</div>
    <div class="menu-item-5">MENU 4</div>
    <div class="menu-item-5">MENU 5</div>
</div>
```
「menu-item-〇」の数字を変えることでメニュー項目を3～5個の範囲で増減できる仕様です．

続いてCSS．
```CSS
/***********************************
*	Menu Item	*
***********************************/
.global-menu {
    overflow: hidden;
    background-color: #FFF;
}

.menu-item-3,
.menu-item-4,
.menu-item-5 {
    box-sizing: border-box;
    float: left;
    text-align: center;
    padding: 10px 0 10px 0;
    font-family: 'Rounded M Plus 1c Bold';
    color: #bbb;
}

.menu-item-3:hover,
.menu-item-4:hover,
.menu-item-5:hover {
    background-color: #FF8A65;
    transition: all 0.5s ease 0s;
    cursor: pointer;
    color: #FFF;
}

.menu-item-3 {
    width: 33.3%;
}

.menu-item-4 {
    width: 25%;
}

.menu-item-5 {
    width: 20%;
}
```
記述してあるのは主にデザインのことで，機能面でそこまで難しいことは書いていません．
widthをpxではなく%で指定しているので，ディスプレイのサイズが変わってもレイアウトが乱れることがないのがポイントです．

### Table（表）
お次はTable，すなわち表です．
```CSS
/***********************************
*	Table	*
***********************************/
table {
    width: 100%;
    border-radius: 10px;
    border-spacing: 0;
    border: none;
    border-left: 2px solid #ddd;
    border-top: 2px solid #ddd;
}

table th {
    background-color: #FFCCBC;
    font-family: 'Rounded M Plus 1c Bold';
}

table tr>* {
    padding: 5px 10px;
    border: none;
    border-right: 2px solid #ddd;
    border-bottom: 2px solid #ddd;
}

table tr:first-child>*:first-child {
    border-radius: 10px 0 0 0;
}

table tr:first-child>*:last-child {
    border-radius: 0 10px 0 0;
}

table tr:last-child>*:first-child {
    border-radius: 0 0 0 10px;
}

table tr:last-child>*:last-child {
    border-radius: 0 0 10px 0;
}
```
表の角も角丸にしてみました．
ここでポイントになるのはこの部分．
```CSS
table tr:first-child>*:first-child {
    border-radius: 10px 0 0 0;
}
```

```CSS
table tr:first-child>*:first-child
```
↑これで各テーブル内の最初の要素と最初の子要素（すなわち左上の要素）を指定して

```CSS
border-radius: 10px 0 0 0;
```
↑選択されたセルの左上の角に10ピクセルの丸みを付けます．

あとは同じような手順で他3つの角にも丸みをつければ完成です．

![スクリーンショット 2023-12-06 104954.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619955/6be9dfaf-f8e8-14b3-be17-3550576a210c.png)

### カラム
最後はカラムです．
簡単なカラムレイアウトを作れるようにしてみました．

![スクリーンショット 2023-12-06 121814.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3619955/48269410-c776-e074-36fa-b7f332a5879c.png)

Wide，Standard，Narrowの3種類の幅を用意しております．

```CSS
/***********************************
*	Column	*
***********************************/
.column {
    margin: auto;
    overflow: hidden;
}

[class*="-narrow"] {
    width: 24%;
}

[class*="-standard"] {
    width: 49%;
}

[class*="-wide"] {
    width: 74%;
}

[class*="column-left"] {
    float: left;
}

[class*="column-right"] {
    float: right;
}
```
CSSはセレクタを多用し，できるだけクラス名が煩雑にならないようにしてみました．
コンテンツ同士が被らないように，敢えてwidthを中途半端な値にしています．

### （おまけ）Gaming
絶対に使うことはないでしょうが，背景を7色に光らせることができます．
技術的には[この拡張機能](https://github.com/zawataku/KITnav_Gaming)からの転用です．
```CSS
@keyframes gaming {
    0% {
        background: #e60000
    }
    14% {
        background: #f39800
    }
    28% {
        background: #fff100
    }
    42% {
        background: #009944
    }
    56% {
        background: #0068b7
    }
    70% {
        background: #1d2088
    }
    85% {
        background: #920783
    }
    100% {
        background: #e60000
    }
}
```

# おわりに
この記事で紹介したCSSフレームワークは，[私のGitHubで配布](https://github.com/zawataku/zawataku_framework)しています．

先述した通りレスポンシブデザインへの対応をはじめとした改善の余地がまだまだあるので，今後もアップデートを続けていこうと思います．

それでは最後までご高覧いただきありがとうございました！