Day25 有料的 CSS 漢堡選單

我們今天要來做幾份漢堡選單。

原理和 Day14 今天我想來點… 純 CSS 的開關 一樣,都是用 inputcheckbox 來儲存狀態好讓其他元素可以抓到。而他本身的狀態使用 label 來遠端遙控。

我先不要一次跳太多步驟。這是一個基本還未完成的版面。

1<input type="checkbox" id="menu">
2<label for="menu">
3  <div></div>
4  <div></div>
5  <div></div>
6  <span class="cover"></span>
7</label>
 1label {
 2  width: 3rem;
 3  height: 3rem;
 4  background: #00c3ff;
 5  display: block;
 6  border-radius: 50%;
 7  display: flex;
 8  flex-direction: column;
 9  align-items: center;
10  justify-content: center;
11  gap: 0.25em;
12  position: relative;
13}
14
15label div {
16  width: 1.5rem;
17  height: 0.25rem;
18  background: #fff;
19  border-radius: 0.25rem;
20}
21.cover {
22  position: absolute;
23  display: block;
24  top: 50%;
25  left: 50%;
26  transform: translate(-50%, -50%);
27  width: 100vmax;
28  height: 100vmax;
29  border-radius: 50%;
30  background: #80e1ff;
31  z-index: -1;
32}

可以看到我們已經有了漢堡選單的樣子。<label> 使用 flex 來垂直排列並且置中,gap 來設定間距,並設定 position: relative 來讓 position: absolute.cover 可以定位到相同位置。

如果已經看不懂的話可以複習:

藍色圓形我們希望能夠填滿整個畫面,所以我們使用 100vmax 來選擇 vwvh 之間比較大的值,這樣可以確保能夠蓋滿畫面但是長寬還是依樣來保持圓形。你會發現只有蓋住螢幕一半是因為我們把她往左上角移動了一半,所以只有一半的圓形在畫面上。沒關係我們為了安全起見設定大一點。最後使用 z-index 來讓他在最底層。

把原本的勾選框隱藏起來再加上內文。漢堡選單裡面當然就是要放漢堡配料,效果如下

漢堡配料 In

 1<input type="checkbox" id="menu" checked>
 2<label for="menu">
 3  <div></div>
 4  <div></div>
 5  <div></div>
 6  <span class="cover">
 7    <ul>
 8      <li>麵包</li>
 9      <li>肉排</li>
10      <li>青菜</li>
11      <li>麵包</li>
12    </ul>
13  </span>
14</label>
 1body {
 2  overflow: hidden;
 3  font-family: system-ui;
 4}
 5input[type="checkbox"] {
 6  display: none;
 7}
 8label {
 9  width: 3rem;
10  height: 3rem;
11  background: #00c3ff;
12  display: block;
13  border-radius: 50%;
14  display: flex;
15  flex-direction: column;
16  align-items: center;
17  justify-content: center;
18  gap: 0.25em;
19  position: relative;
20  cursor: pointer;
21}
22
23label div {
24  width: 1.5rem;
25  height: 0.25rem;
26  background: #fff;
27  border-radius: 0.25rem;
28  transition: all 0.3s;
29}
30.cover {
31  position: absolute;
32  display: block;
33  top: 50%;
34  left: 50%;
35  transform: translate(-50%, -50%);
36  width: 0;
37  height: 0;
38  border-radius: 50%;
39  background: #80e1ff;
40  z-index: -1;
41  transition: all 0.3s;
42  overflow: hidden;
43}
44input:checked ~ label > .cover {
45  width: 250vmax;
46  height: 250vmax;
47  border-radius: 50%;
48}
49
50ul {
51  position: absolute;
52  top: 50%;
53  left: 50%;
54  width: 100vw;
55  color: #fff;
56  font-size: 3em;
57  list-style: none;
58  font-weight: 700;
59}

最後是漢堡動畫,這裡就要發揮你自己的創意了。原理不難,這裡提供一個我現在想到的做法。我想要最上面的和最下面的旋轉 45 度,中間的變短到消失。所以我們先把中間的設定 width: 0; height: 0; ,然後我們把最上面的和最下面的設定 transform: rotate(45deg);,這樣就會旋轉 45 度了。這樣能夠做出一個箭頭:

箭頭

1input:checked ~ label > div:first-child {
2  transform: rotate(-45deg);
3}
4input:checked ~ label > div:nth-child(2) {
5  width: 0;
6}
7input:checked ~ label > div:nth-child(3) {
8  transform: rotate(45deg);
9}

再來做一個也很常見的打叉,為了方便我們乾脆全部使用 absolute 定位。成果如下:

https://codepen.io/edit-mr/pen/zYyyEgz

打叉

 1body {
 2  overflow: hidden;
 3  font-family: system-ui;
 4}
 5input[type="checkbox"] {
 6  display: none;
 7}
 8label {
 9  width: 3rem;
10  height: 3rem;
11  background: #00c3ff;
12  display: block;
13  border-radius: 50%;
14  position: relative;
15  cursor: pointer;
16}
17
18label div {
19  position: absolute;
20  width: 1.5rem;
21  height: 0.25rem;
22  background: #fff;
23  border-radius: 0.25rem;
24  transition: all 0.3s;
25  top: 50%;
26  left: 50%;
27  transform: translate(-50%, -50%);
28}
29.cover {
30  position: absolute;
31  display: block;
32  top: 50%;
33  left: 50%;
34  transform: translate(-50%, -50%);
35  width: 0;
36  height: 0;
37  border-radius: 50%;
38  background: #80e1ff;
39  z-index: -1;
40  transition: all 0.3s;
41  overflow: hidden;
42}
43input:checked ~ label > .cover {
44  width: 250vmax;
45  height: 250vmax;
46  border-radius: 50%;
47}
48
49ul {
50  position: absolute;
51  top: 50%;
52  left: 50%;
53  width: 100vw;
54  color: #fff;
55  font-size: 3em;
56  list-style: none;
57  font-weight: 700;
58}
59input:checked ~ label div:first-child {
60  left: 25%;
61  top: 50%;
62  transform: rotate(45deg);
63}
64input:checked ~ label div:nth-child(2) {
65  width: 0;
66}
67input:checked ~ label div:nth-child(3) {
68  left: 25%;
69  top: 50%;
70  transform: rotate(-45deg);
71}
72label > div:first-child {
73  top: calc(50% - 0.5rem);
74}
75label > div:nth-child(3) {
76  top: calc(50% + 0.5rem);
77}

你以為這樣就結束了? 還記得我們昨天講的 Day24 CSS 相融黏滯效果 嗎? 我們可以把他加上去讓他更有質感。

這是一個會四處噴射漢堡選單

發射漢堡選單

1<input type="checkbox" id="menu" checked>
2<label for="menu">
3  <div>🥩</div>
4  <div>🥬</div>
5  <div>🧀</div>
6  🍔
7</label>
 1body {
 2  overflow: hidden;
 3  font-family: system-ui;
 4}
 5
 6input[type="checkbox"] {
 7  display: none;
 8}
 9
10label {
11  width: 5rem;
12  height: 5rem;
13  background: #00c3ff;
14  display: block;
15  border-radius: 50%;
16  position: relative;
17  cursor: pointer;
18  margin: 1em auto;
19}
20
21div {
22  position: absolute;
23  top: 50%;
24  left: 50%;
25  transform: translate(-50%, -50%);
26  width: 3rem;
27  height: 3rem;
28  border-radius: 50%;
29  background: #00c3ff;
30  z-index: -1;
31  transition: all 0.3s;
32  overflow: hidden;
33}
34
35input:checked ~ label > div:nth-child(1) {
36  left: calc(50% - 5rem);
37}
38
39input:checked ~ label > div:nth-child(2) {
40  top: calc(50% + 5rem);
41}
42input:checked ~ label > div:nth-child(3) {
43  left: calc(50% + 5rem);
44}
45
46label,
47div {
48  display: flex;
49  align-items: center;
50  justify-content: center;
51  font-size: 2.5rem;
52  user-select: none;
53}
54
55div {
56  font-size: 1.5rem;
57}

user-select: none; 可以讓使用者無法選取文字,這樣就不會在點擊時有文字被選取的問題了。

加上昨天的相黏效果,變得更可愛了。

https://codepen.io/edit-mr/pen/NWeeYRq

相黏效果

 1body {
 2  overflow: hidden;
 3  font-family: system-ui;
 4  min-height: 100svh;
 5}
 6input[type="checkbox"] {
 7  display: none;
 8}
 9label {
10  width: 5rem;
11  height: 5rem;
12  display: block;
13  position: absolute;
14  cursor: pointer;
15  left: 50%;
16  transform: translate(-50%, -50%);
17}
18.box div {
19  width: 4rem;
20  height: 4rem;
21}
22.box div,
23label {
24  top: 50%;
25  border-radius: 50%;
26  background: #00c3ff;
27}
28.box div,
29.food,
30.food div {
31  position: absolute;
32  left: 50%;
33  transform: translate(-50%, -50%);
34  transition: 0.3s;
35}
36input:checked ~ .box div:first-child,
37input:checked ~ .food div:first-child {
38  left: calc(50% - 4rem);
39}
40input:checked ~ .box div:nth-child(2),
41input:checked ~ .food div:nth-child(2) {
42  top: calc(50% + 4rem);
43}
44input:checked ~ .box div:nth-child(3),
45input:checked ~ .food div:nth-child(3) {
46  left: calc(50% + 4rem);
47}
48.box div,
49label {
50  user-select: none;
51  filter: blur(10px);
52}
53.box {
54  background: #fff;
55  filter: contrast(20) hue-rotate(45deg);
56  height: 100svh;
57}
58.food,
59.food div {
60  top: 50.3%;
61  user-select: none;
62  pointer-events: none;
63}
64input:checked ~ .food div {
65  font-size: 1.5rem;
66}
67.food div {
68  font-size: 0rem;
69}
70.food div:last-child {
71  font-size: 2rem;
72}

手機版的淘寶之前有使用過類似的效果製作分享選單喔~

因為相黏效果有先模糊,裡面的 Emoji 文字也會被模糊,所以我們在後面又做一個只有文字的 .food 來顯示文字。設定 pointer-events: none 就可以讓他不會被點擊到了,直接穿透去點擊下面的 label

背景顏色一定要記得設定,不然只會糊再一起沒有相黏效果。這是我 debug 半小時之後才想到的...

以上就是我今天的分享,歡迎在 InstagramGoogle 新聞追蹤毛哥EM資訊密技,也歡迎訂閱我新開的YouTube頻道:網棧

我是毛哥EM,讓我們明天再見。

Posts in this Series