0%

S2:切版練習:毛小孩星球

完成作品CodePen連結

此文章所做的筆記,僅為提醒自己要多加注意的地方。

本文引用之圖片均來自Alpha Camp

作業筆記

起手式 Rest default CSS 還原瀏覽器預設設定

每家瀏覽器都有預設不同的 CSS 樣式,造成前端工程師網頁開發上一個頭痛的問題:
開發時用 CSS 設計好整齊美麗的排版,在 Google Chrome 上看起沒問題,用 IE 打開卻全變了樣,且市面上還有 Firefox、Safari、Opera 等其他家瀏覽器,

所以實務開發中,CSS起手式通常會是 Reset CSS,先將各大瀏覽器的預設樣式還原,有個乾淨的開始,再來制訂專案的樣式。

可以直接使用開源的 CSS Reset 工具如:

  1. Reset CSS ,這是 CSS 大師 Eric Meyer 整理出的版本
  2. Normalize.css 這是 Bootstrap 目前已經內建使用的版本
  3. 或是自行制訂

header 固定置頂

常常看到很多網頁,可以將header固定在最上方,不會因為頁面下滑消失。
我們可以使用 position: fixed 來固定元素位置。

再通過 z-index 可以定義元素的層級,愈大的數字會放在愈上層,愈小的數字會放在愈下層,而視窗位於 0 的位置。
將數值設定為 999 ,基本 header 元素就很難被其他元素覆蓋掉,導覽列就會固定在最上層。

em vs. rem

rem 和 em 同樣是相對單位,只是參照的對象不同。 em 參照的對象是父元素, rem 是 root em 的意思, 參照的是根元素,就是 html 層級的字體大小,一般瀏覽器的預設值是 16 px。
使用 rem 的好處是,專案一複雜,很容易忘記父元素是多少大小,用 rem 不用特別去記。或當父元素字體大小突然被改動時,用 rem 也不會受到連帶影響。

絕對定位 position:absolute

絕對定位 position: absolute 指的是子元素根據父元素做定位,但父元素CSS要設定position: relative,否則會根據html body標籤來設定位置。
在這個案例中,父元素是 header(跟body位置一樣寬且置頂),子元素是 nav。
假設 top 是 0,子元素會貼齊父元素的最頂端。
看手機設計稿,此案導覽列是貼齊在 header 的下面,所以要設定 top:100%。子元素移動到父元素正下方。

本案導覽列原本是沒有特別設定寬度的,瀏覽器預設為 auto
一般情況下,導覽列因為是 block element,因此會想辦法佔滿父元素的寬度和高度空間。
然而,在設定為絕對定位後,元素已經完全脫離文字流了,本身寬度和高度大小會透過內容決定
所以目前 .nav 的寬度只有 4 個字元寬。手動將寬度設為 100% 和父元素同寬,文字就會置中。

使用line-height 來設定文字的垂直置中

要做文字的垂直置中的效果,可能會直覺想到 position 或是 flexbox,
這邊因為只有文字,所以可以使用 line-height 這方法來讓 logo 文字垂直置中。

將文字的 line-height 設定和父元素同高即可。

使用input-checkbox來製作漢堡排使導覽列收合

1.先加入html標籤

1
2
3
4
5
6
7
8
9
10
11
12
13
<header>
<a href="#" class="navbar-brand">毛小孩星球</a>
<!-- 加入input-checkbox -->
<input type="checkbox" class="nav-toggle" id="nav-toggle">
<!-- 加上導覽列 -->
<nav class="nav">
<ul class="nav-list">
<li class="nav-item"><a href="#activity" class="nav-link">近期活動</a></li>
<li class="nav-item"><a href="#album" class="nav-link">狗兒相片</a></li>
<li class="nav-item"><a href="#adoption" class="nav-link">領養資訊</a></li>
</ul>
</nav>
</header>

2.原先的nav先設定不顯示

1
2
3
4
5
6
7
8
9
nav {
/*依據 Header 定位*/
position: absolute;
top: 100%;
background: #ffffff;
width: 100%;
/*原本先不顯示*/
display: none;
}

3.使用 pseudo-class 控制「被勾選」時樣式,及使用 ~ 選定同一層後方元素

1
2
3
.nav-toggle:checked ~ .nva {
display: block ;
}

這樣就可以製作出一個陽春版的漢堡排。

4.使用 transition 和 transform 優化收合的轉場效果

  • transition 屬性是一個縮寫,冒號後面可以放四個屬性值:
    transition: property duration timing-function delay;依序代表:
    • transition-property:載明哪個屬性要使用這個效果,例如我們的目標是和顯示有關的 display 屬性。
    • transition-duration:這個效果持續發生的時間,單位是秒,如果是 0 點幾,0 可以不寫。例如我們希望持續 0.2 秒的話可寫 .2s 。
    • transition-timing-function:效果的變化速度,可以寫屬性名稱,例如 ease-in 是緩慢的開始,也可以自由定義 cubic-bezier 函數,easing.net 提供一張好用的速查表,可前往試用後複製想要的函數。
    • transition-delay:先延遲多久之後再開始這個效果,單位和寫法同transition-duration。
  1. 再nav加入 transition
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    nav {
    /*依據 Header 定位*/
    position: absolute;
    top: 100%;
    background: #ffffff;
    width: 100%;
    /*原本先不顯示*/
    display: none;
    /*設定display的過渡動畫變化效果*/
    transition: display .2s ease-out;
    }

最後發現沒有變化
畫面沒有變化是因為 display 只有 100% 完全顯示和 0% 完全不顯示兩個狀態,無法做到漸變的效果。

  1. transform
    為了解決這個問題,我們再來多認識一個 CSS 屬性:transform。
    transform 的 MDN 文件,裡面有屬性變化效果的範例。

使用 transform: scale(1,0); 來取代 display: none;
及 transform: scale(1,1); 來取代 display: block;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
nav {
/*依據 Header 定位*/
position: absolute;
top: 100%;
background: #ffffff;
width: 100%;
/*改設定transform的過渡動畫變化效果*/
transition: transform .2s ease-out;
/*由display改為transform,一開始設定(x,y)比例為(1,0)為不顯示*/
transform: scale(1,0);
}

.nav-toggle:checked ~ .nav {
/*由display改為transform,設定(x,y)比例為(1,1)*/
transform: scale(1, 1)
}

此時能夠發現有轉場效果了,但是卻從中間開闔。

  1. 使用 transform-origin 設定 transform 變化起點在上方
    讓導覽列從上方開始做上下收放,可使用 transform-origin 這個屬性來達成。
    預設的屬性值是 center,代表 transform 效果的起始點是在元素的中心。
    可以看 MDN還有哪些屬性 transform-origin

增加transform-origin屬性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
nav {
/*依據 Header 定位*/
position: absolute;
top: 100%;
background: #ffffff;
width: 100%;
/*設定transform的過渡動畫變化效果*/
transition: transform .2s ease-out;
/*由display改為transform,一開始設定(x,y)比例為(1,0)為不顯示*/
transform: scale(1,0);
/*設定變化原點在上方*/
transform-origin: top;
}

.nav-toggle:checked ~ .nav {
/*由display改為transform,設定(x,y)比例為(1,1)*/
transform: scale(1, 1)
}
  1. 最後使用 opacity 讓使用者不會看到開關時文字壓縮
    在.nav-item上加上opacity: 0 以及 .nav-toggle:checked時.nav-item的樣式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    .nav-item {
    margin: 1.4rem 0;
    opacity: 0; /*完全透明*/
    }

    .nav-toggle:checked ~ .nav .nav-item {
    transition: opacity 0.2s ease-out 0.15s; /*透明過場設定,最後一個參數為當checked被執行時,緩150毫秒進行過場動畫*/
    opacity: 1; /*不透明*/
    }

製作 hamburger 樣式及位置

利用label 的for 屬性會和input 的 id綁定,就可以點label的時候去觸及input
先在html上加入 label,再加上span打上三,暫時製作一個陽春的漢堡排

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<header>
<a href="#" class="navbar-brand">毛小孩星球</a>
<!-- hamberger -->
<input type="checkbox" class="nav-toggle" id="nav-toggle">
<!-- 加上導覽列 -->
<nav class="nav">
<ul class="nav-list">
<li class="nav-item"><a href="#activity" class="nav-link">近期活動</a></li>
<li class="nav-item"><a href="#album" class="nav-link">狗兒相片</a></li>
<li class="nav-item"><a href="#adoption" class="nav-link">領養資訊</a></li>
</ul>
</nav>
<!-- 增加label標籤 -->
<label for="nav-toggle" class="navbar-toggle-label">
<span class="hamburger"></span>
</label>
</header>

設定漢堡排位置
先選定 navbar-toggle-label ,使用絕對定位,讓漢堡排從文字流離開
然後設定top和bottom都為0,代表這個元素高度跟父元素 header 相等是 60px
最後使用display: flex 和 align-items 來設定垂直置中。

1
2
3
4
5
6
7
8
.navbar-toggle-label {
position: absolute;
top: 0;
bottom: 0;
right: 7.5%;
display: flex;
align-items: center;
}

進階版漢堡排:使用span畫線
先把國字三刪除,接著改寫 .hamburger的樣式,畫出第一條具備美感的漢堡排中央橫線。
選定漢堡.hamburger,寬度設定 30px,高度是 3px,背景顏色則是 #267b98。

.hamburger {
width: 30px;
height: 3px;
background: #267b98;
}

使用偽元素增加漢堡另外兩條線

其他兩條都跟中間這一條外觀相同,所以我們在選擇器 .hamburger後加兩個偽元素選擇 hamburger::before 和 .hamburger::after。
但我們還沒有給它任何的 content,還沒有任何的內容,所以基本上是看不到它。
我們需要給hamburger::before 和 .hamburger::after一個 content,屬性值設定為一個空值,因為我們只需要利用這個元素的空間來做樣式,不需要內容。

1
2
3
4
5
6
7
8
9
10
11
12
.hamburger,
.hamburger::before,
.hamburger::after {
width: 30px;
height: 3px;
background: #267b98;
}
.hamburger::before,
.hamburger::after {
/*給一個空的內容*/
content: "";
}

設定偽元素的位置

如果想給 .hamburger:before 和 .hamburger::after 設定在 .hamburger 的上下方,
應該給 .hamburger設定 position: relative
.hamburger:before 和 .hamburger::after 設定position: absolute

absolute是相對於自己最近的父元素來定位的
如果不給.hamburger相對定位,那麼.hamburger:before 和 .hamburger::after的絕對定位absolute就是相對於body來定位的

relative是相對於自己來定位的,例如:.hamburger{position:relative;top:-50px;},這時.hamburger會以他原本的位置上移50px。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.hamburger,
.hamburger::before,
.hamburger::after {
width: 30px;
height: 3px;
background: #267b98;
}
.hamburger {
position: relative;
}

.hamburger::before,
.hamburger::after {
position: absolute;
/*給一個空的內容*/
content: "";
}

接著移動before和after兩個元素的上下位置

1
2
3
4
5
6
7
.hamburger::before {
bottom: 8px;
}

.hamburger::after {
top: 8px;
}

會看到兩個元素已經各上下移動8px,但是偏了一邊,只要在設定absolute的時候給兩個元素left 0即可
完整css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.hamburger,
.hamburger::before,
.hamburger::after {
width: 30px;
height: 3px;
background: #267b98;
}
.hamburger {
position: relative;
}

.hamburger::before,
.hamburger::after {
position: absolute;
left: 0;
/*給一個空的內容*/
content: "";
}

.hamburger::before {
bottom: 8px;
}

.hamburger::after {
top: 8px;
}

隱藏input-checkbox

給input-checkbox設定上CSS樣式屬性 visibility: hidden;
就會隱藏,但是會看到brand歪一邊,這時候再給input-checkbox設定position: absolute,讓他抽離文字流即可。

1
2
3
4
5
.navbar-toggle {
/*不佔空間*/
visibility: hidden;
position: absolute;
}

display: none 與 visibility: hidden 的差異 display: none 與 visibility: hidden 都是隱藏元素的方法,差別在於 display: none 會一口氣使操作對象從文字流中拔除,而 visibility: hidden 則像是用一塊白布蓋起來的感覺,畫面上不顯示,但還是會佔一個空間:

在我們剛剛實作的案例中,將 visibility: hidden 搭配上 position: absolute; ,故元素會從文字流中移除,完全和 display: none 是一樣的效果。
在我們的情境中這兩種做法都可以,一併介紹給大家知道。
未來你可以根據需求判斷要用哪一個方法比較合適。

grid-auto-flow 與 grid-auto-rows

grid-auto-flow 是控制當沒有宣告子元素要被擺在網格的特定位置時,子元素將根據特定的流向被自動擺放到網格當中。
grid-auto-flow 的預設值為 row,意思是子元素將逐列被擺放到網格中。
假設第一行有兩列,放滿後會被推向下一行,若是有設定grid-auto-rows高,那麼會自動生成下一行高,並把元素推下一行的第一列。

1
2
3
4
5
.container{
display: grid;
grid-auto-flow: row;
grid-auto-rows: 100px;
}

換個方向可以手動更改grid-auto-flow 為 column,意思是子元素將逐行被放到網格中。
假設第一行只有一列,第二行也只有一列,子元素會由上而下,放滿後會被推向下一列第一行,若是有設定grid-auto-columns寬,那麼自動生成的下一列寬,並把元素推下一列的第一行。

1
2
3
4
5
.container{
display: grid;
grid-auto-flow: column;
grid-auto-columns: 100px;
}

grid-template-areas

可以透過父層先劃分好格子,然後再選擇各個子元素,將各個子元素使用grid-area各自命名,最後回到父層使用grid-template-areas來安排子元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.banner-wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(2, 250px);
grid-template-areas:
"main main main main"
"left left right right";
grid-gap: 0.5rem;
}

.main-banner {
grid-area: main;
}

.sub-banner-left {
grid-area: left;
}

.sub-banner-right {
grid-area: right;
}

Welcome to my other publishing channels