iT邦幫忙

2024 iThome 鐵人賽

DAY 11
0
Modern Web

Dive into CSS Challenge:從問題到解決方案的實踐之旅系列 第 11

Day 11 - CSS Challenge #7:Notification、Menu、Search(中)

  • 分享至 

  • xImage
  •  

題目

CSS Challenge Day7

  • Notification Card
    https://ithelp.ithome.com.tw/upload/images/20240921/201694035gAEy0oBdC.png

題目除了基本 Notification Card介面樣式以外,還有兩個重要的介面

  • Menu
    https://ithelp.ithome.com.tw/upload/images/20240921/201694033Smw1xJZIi.png

  • Search
    https://ithelp.ithome.com.tw/upload/images/20240921/20169403GTSfkpkerf.png

上面的圖是題目,而我們要做出幾乎一樣的樣子,題目中還有附上出題官方的CodePen,也有附上給我們解題用的template,當我們真的不會的時候,還是可以參考他們的寫法,所以沒有想像中困難。

我做好的此題CSS Challeage解答

那麼我們就開始吧。

前情提要

我們上次已經做完 Notification Card - 藍色 header 的部分,長這樣:
https://ithelp.ithome.com.tw/upload/images/20240922/20169403CjvfyYuZS2.png

那我們今天先來做卡片白色區塊的訊息部分。

開始解題

Notification Card - 白色 content

1. 基本架構

<div class="content">
	<div class="line"></div>
	<div class="notify">
		<div class="dot"></div>
		<span class="time">9:24 AM</span>
		<p><b>John Walker</b>posted a photo on your wall.</p>
	</div>
</div>

首先,一樣先開版,把結構作出來。
通知有三則,但我示範就不寫出來,大家記得 copy 三段 .notify 並且把內文改成跟題目一樣的其他通知。

畫面上有一條灰色直線,所以我做一個 div 取名 .line
接下來的是一則通知包裹在一個 div 裡面,所以將這個 div 取名為 .notify

他裡面的結構分別是藍色空心圓點,取名 .dot
小字的時間,這邊我用 span 來製作,取名 .time
主要的通知文字,這邊我用 p 來製作,裡面人名的部分有粗體,所以直接給他包一個 b
這樣基礎架構就完成了,剛做好還沒有寫樣式的時候會是這樣:
https://ithelp.ithome.com.tw/upload/images/20240922/20169403NA02S49ocT.png

2. 灰色線條樣式

.content {
    ...
    .line {
		position: absolute;
		background-color: #EBEBEB;
		width: 3px;
		top: 0;
		left: 27px;
		bottom: 0;
	}
}

我們上一集已經設定過 .content 了,這次就直接在裡面加入 .line 的樣式。

先設定它的 position: absolute 讓我們能定位他,接著一樣用第一天教的小工具去吸色,改好他的背景色,設定好寬度,基本上就差不多了。
https://ithelp.ithome.com.tw/upload/images/20240922/201694030CdstSq5Zd.png

3. 每一則通知的樣式

.content {
    ...
    .notify {
		position: relative;
		margin: 25px 20px 25px 40px;
		cursor: pointer;
        &:hover {
			color: $blue;
		}
    }
}

因為通知裡面的 .dot 會需要用 absolute 定位的方式來製作,所以這邊先把 .notify 加上 position: relative

接著視覺上檢查調整一下 padding 的部分。

由於題目是滑鼠指上時,整則通知的文字要變成藍色,且我看他並沒有需要漸變效果,所以這邊我就只有加上 cursor: pointer 及滑鼠指上的變色,我就沒有做 transition
剛做好的時候長這樣:
https://ithelp.ithome.com.tw/upload/images/20240922/20169403Y2l2YaVoLV.png

.content {
    ...
    .notify {
		.time {
			display: block;
			font-size: 11px;
		}
		.p {
			font-size: 15px;
			line-height: 20px;
			.b {
				font-weight: 600;
				display: inline-block;
				margin-right: 5px;
			}
		}
    }
}

那我們就再去裡面調整 .time p 各自的文字樣式,字體大小,字距行高等等。調整完之後長這樣:
https://ithelp.ithome.com.tw/upload/images/20240922/20169403eonrk41QnD.png

接著來做藍色空心圓點的部分

.content {
    ...
    .notify {
        ...
		.dot {
			position: absolute;
			width: 7px;
			height: 7px;
			border: 2px solid $blue;
			background-color: #fff;
			box-shadow: 0 0 0 3px #fff;
			top: 0;
			left: -17px;
			border-radius: 100%;
			z-index: 3;
		}
    }
}

一般這種空心圓點,大部分有概念的人應該都知道,就是做一個 div 給他個藍色的 border,使用 border-radius 讓他變成圓形,中間 background-color 填白色就好。

但是他這顆比較特別是,他的藍色 border 外面還有一圈白色。
這個部分對初學的人可能會有點 tricky,但也可能有人完全沒有注意到這個小細節...
https://ithelp.ithome.com.tw/upload/images/20240922/20169403I2qobN8VzG.png
其實這個外圍的白色不難,我們只要用 box-shadow 就可以做到,這邊我設定的是 box-shadow: 0 0 0 3px #fff

box-shadow: 0 0 0 3px #fff 中,各數字代表不同的含義:

  • 第一個 0:水平偏移量,控制陰影向左或向右的偏移。
  • 第二個 0:垂直偏移量,控制陰影向上或向下的偏移。
  • 第三個 0:模糊半徑,控制陰影的模糊程度(0 表示無模糊)。
  • 3px:擴展半徑,控制陰影的擴展範圍。
  • #fff:陰影的顏色,這裡為白色。

這樣的設定使陰影均勻地包圍元素,視覺上看起來就像一條 3px 左右的白色線條包在外面似的,達到跟題目一樣的效果,這樣卡片的介面開版就做好了。
https://ithelp.ithome.com.tw/upload/images/20240922/20169403VozBZlBWSn.png

4. 初次載入畫面時 .notify 的動畫

接著我們來處理初次載入畫面的時候,.notify 的動畫效果。

@keyframes fade-up {
	from {
		opacity: 0;
		transform: translate(0, 50px);
	}
	to {
		opacity: 1;
		transform: translate(0, 0);
	}
}

我先寫了一個 fade-up 動畫,從完全透明並向下偏移 50px 開始,逐漸變為完全不透明並回到原始位置 translate(0, 0)
然後把這個動畫套用到我們 .notify 的元素內。

.notify {
    ...
	@for $i from 2 through 4 {
		&:nth-child(#{$i}) {
		animation: fade-up .5s ease-out ($i/5 + s);
		animation-fill-mode: both;
	}
}

這邊我不直接把動畫寫在 .notify 上,是因為它們的出現有延遲,不像這題的其他動畫,都是單純的移動跟出現,這邊動畫的 .notify 是一則一則出現的,所以我們需要去計算這個延遲。

  • 使用 @for 迴圈來針對每個第 2 到第 4 個子元素 nth-child(2)nth-child(4) 應用動畫。

  • 這是因為 .notify 內的第一個元素是 .line 灰色線條,而他不需要做這個延遲出現的動畫。

  • animation 設定為剛剛做好的 fade-up,持續 0.5 秒,並且每個元素的動畫延遲 (i/5) 秒以產生依次淡入的效果。

  • (i/5) 這段是指在動畫的延遲時間上根據元素的位置進行計算。在這裡,$iSass 的變數,它從 24 迴圈執行。

    • 第二個元素會有延遲時間 (2/5) 秒,也就是 0.4 秒。
    • 第三個元素會有延遲時間 (3/5) 秒,也就是 0.6 秒。
    • 第四個元素會有延遲時間 (4/5) 秒,也就是 0.8 秒。

這樣可以讓每個元素按順序依次出現並淡入,達成我們想要的效果。

這樣整個 Notification Card 就做好了,接著我們來製作上面的 Search Input。


Search

https://ithelp.ithome.com.tw/upload/images/20240921/20169403GTSfkpkerf.png

1. 樣式

<header>
	<div class="menuIcon"></div>
	<h1>Notifications</h1>
	<button class="searchIcon">
		<i class="fa fa-search search-icon"></i>
	</button>
    <input class="searchInput" type="text" placeholder="Search ..." /> //增加這句
</header>

我們先在原先的 .searchIcon 後面增加一個 input 取名為 .searchInput
https://ithelp.ithome.com.tw/upload/images/20240922/201694031MybgRtPvy.png

header {
	.searchInput {
		position: absolute;
		right: 55px;
		z-index: 5;
		box-sizing: border-box;
		background-color: #fff;
		outline: none;
		font-size: 12px;
		padding: 8px 16px;
		border-radius: 17px;
		width: 77%;
	}
}

先把 position: absolute 加上後,由於他是要從右邊滑出來,所以我讓他的定位點是在右邊,這裡我設定 right: 55px

https://ithelp.ithome.com.tw/upload/images/20240922/20169403pwk1Z3Ss0O.png
記得加上 outline: none:focusinput 的外框消失。

再依據視覺上看起來的樣式,調整一下上下左右的 padding border-radius 跟文字大小等等,就差不多可以了。

做好之後長這樣:
https://ithelp.ithome.com.tw/upload/images/20240922/20169403t3yITzg1o9.png

2. 開關 SearchInput

.searchInput {
    ...
    opacity: 0;
    transition: all ease-in-out .3s;
    transform: translateX(15px);
    
    &.show {
		opacity: 1;
		transform: translateX(0);
	}
}

動畫部分的原理是這樣的,當使用者點擊旁邊的 search icon 時,我們寫一段 javascript 去檢查我們目前的這個 search input 上面有沒有 .show 這個樣式,沒有的話加上,有的話移除。

所以我們可以先來修改一下 .searchInput,先把他的透明度改成 0,因為一開始的時候是看不到這個 input 的。這時候當然要在 .show 裡面同步加上透明度 1,這樣才會如願顯示。

transform: translateX(15px) 加上,讓整個 search input 往右邊位移 15px,並且在 .show 裡面同步加上 transform: translateX(0) 讓他回到原點。

因為動態是做在 .searchInput 本人身上,所以不要忘記在他身上加上漸變用的 .transition: all ease-in-out .3s

然後我們來設定JS,先 include 這個 library
https://ithelp.ithome.com.tw/upload/images/20240922/20169403ijschoD5TH.png

$(".searchIcon").bind('click', function(){
	$('.searchInput').toggleClass('show');
});

然後我們加上 javascript,去 toggle 增加或刪除 .show 這個 class,這樣我們的按鈕就可以操作了。

雖然按鈕可以操作,但一定有人發現問題了。
就是雖然按鈕看起來消失了,但我們滑鼠在 .menuIcon 的位置附近晃,尤其是靠近Icon右上角圓點的地方,竟然會出現輸入的滑鼠游標?

因為他雖然看不到,可是他只是透明的而已,而且在那個位置他擋住 .menuIcon 讓他的右半邊都按不到,這是蠻嚴重的問題,讓我們來修正吧~

.searchInput {
    ...
    pointer-events: none;
    
    &.show {
        ...
		pointer-events: all;
	}
}

這時候就回到剛剛 .searchInput 的地方,加上一句 pointer-events: none,用 CSS 控制讓他不接受任何滑鼠的動作。

那同樣的,記得在 .show 這邊加回來讓滑鼠可以動作的語法 pointer-events: all 這樣就差不多完成了。

由於篇幅太長了,我決定再分篇寫,下一篇再來寫後面的 Menu。


Wrap up and go home

希望改變了這種按照步驟的寫法,能讓更多人看得懂,也能跟我一樣喜歡上寫CSS。

那今天就先到這裡,明天我們再繼續來玩下一集。


上一篇
Day 10 - CSS Challenge #7:Notification、Menu、Search(上)
下一篇
Day 12 - CSS Challenge #7:Notification、Menu、Search(下)
系列文
Dive into CSS Challenge:從問題到解決方案的實踐之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言