JavaScript 提升(Hoisting)


在瞭解提升(Hoisting)之前,先讓我們看看 JavaScript 中變數的有效範圍(Scope)。

變數的有效範圍 (Scope)

在 ES6 之前,JavaScript 變數有效範圍的最小單位是以 function 做分界的。

1
2
3
4
5
6
7
8
9
10
11
var x = 1;

var fn = function(y) {

var x = 100;
return x + y;
};

console.log(fn(50)); // 150

console.log(x); // 1

由於函式 fn() 裡面再次定義了變數 x,所以當我們執行 fn(50) 時,會將 50 作為參數傳入 fn()y,那麼 return x + y 的結果自然就是 100 + 50150 了。

因為「切分變數有效範圍的最小單位是 “function” 」,所以在函式區塊內透過 var 定義的 x 實際上只屬於這個函式。 換句話說,外面的 x 跟 function 內的 x 其實是兩個不同的變數,所以最後一行印出的 x 是 1 而不是 100 。

如果 function 內部沒有 var x 呢?

如果自己的 function 內如果找不到,就會一層層往外找,直到全域變數為止:

範例:

1
2
3
4
5
6
7
8
9
var x = 1;
var fn = function(y) {

// 內部找不到 x 就會到外面找,直到全域變數為止。
// 都沒有就會報錯:ReferenceError: x is not defined
return x + y;
};

console.log(fn(50)); // 51

要注意的是, function 可以讀取外層已經宣告的變數,
但外層拿不到裡面宣告的變數。

沒有 var 宣告的變數會變成全域變數

1
2
3
4
5
6
7
8
9
10
11
var x = 1;

var fn = function(y) {

x = 100;
return x + y;
};

console.log(fn(50)); // 150

console.log(x); // 100

由於在 function 內沒有重新宣告 x 變數,使得 x = 100 跑去變更了外層的同名變數 x

提升 (Hoisting)

一般在寫程式的時候,我們都會定義好變數,然後才去使用它,如果在尚未定義的情況下,直接去使用這個變項,通常都會出現錯誤訊息!

然而,在 javascript 中有一個蠻特別的概念是 hoisting ,指的是在 JavaScript 中,它會把定義的變數移到最前面先執行。

JavaScript 僅提升宣告的部分,而不是初始化。如果在使用該變數後才宣告和初始化,那麼該值將是 undefined。

1
2
3
4
5
6
7
8
9
10
11
12
13
var x = 1;

var fn = function(y) {

console.log(x); // undefined

var x = 100;
return x + y;
};

console.log(fn(50)); // 150

console.log(x); // 1

上面的例子,實際上在瀏覽器 (或者編譯器) 的眼中,是長這樣的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var x = 1;

var fn = function(y) {
var x;
console.log(x); // undefined


x = 100;
return x + y;
};

console.log(fn(50)); // 150

console.log(x); // 1

除了變數以外,函式也有提升。

透過「函式宣告」方式定義的函式可以在宣告前使用 (函式提升) :

1
2
3
4
5
6
7
fn(2);    // 4


function fn(number) {

return number * number;
}

而透過「函式運算式」定義的函式則是會出現錯誤:

1
2
3
4
5
6
7
fn(2);    // TypeError: square is not a function


var fn = function (number) {

return number * number;
};

與變數提升的差別在於變數提升只有宣告被提升,而函式的提升則是包括內容完全被提升。

參考文獻

  1. https://ithelp.ithome.com.tw/articles/10191549

  2. https://developer.mozilla.org/zh-TW/docs/Glossary/Hoisting

  3. https://pjchender.blogspot.com/2015/12/javascript-hoisting.html

JavaScript 函式(Function)


JavaScript 中函式是一種物件

「函式」指的是將一或多段程式指令包裝起來,可以重複使用,也方便維護。

宣告函式的方法有好幾種,但不管是什麼方式,通常一個函式會包含三個部分:

  • 函式的名稱(也可能沒有名稱,稍後會提到)
  • 在括號 ( ) 中的部分,稱為「參數 (arguments) 」,參數與參數之間會用逗號 , 隔開
  • 在大括號 { } 內的部分,內含需要重複執行的內容,是函式功能的主要區塊。

定義函式的方式

常見定義函式的方式有這幾種:

  • 函式宣告(Function Declaration)
  • 函式運算式(Function Expressions)
  • 函式關鍵字(Function Keyword)

函式宣告(Function Declaration)

「函式宣告」應該是屬於最常見的用法:

1
2
3
4
function 名稱([參數]) {
// 函數內容 ...

}

範例:

1
2
3
function fn(number) {
return number * number;
}

函式運算式(Function Expressions)

將一個函式透過 = 指定給某個變數,以下範例為匿名函式(不具名字的函式):

1
2
3
4
var fn = function (number) {

return number * number;
};

也可以賦予函式名稱:

1
2
3
4
var fn = function func(number) {

return number * number;
};

請注意,這個名字只在「自己函式的區塊內」有效,脫離函式自身區塊後,變數 func 就不存在了:

1
2
3
4
5
6
var fn = function func(number) {
console.log( typeof func ); // "function"
return number * number;
};

console.log( typeof func ); // undefined

函式關鍵字(Function Keyword)

使用 Function ( F 大寫) 這個關鍵字來建立函式物件。 使用時將參數與函式的內容依序傳入 Function,就可以建立一個函式物件了:

1
var fn = new Function('number', 'return number * number');

透過 new Function 所建立的函式物件,每次執行時都會進行解析「字串」(如 'return number * number' ) 的動作,運作效能較差,所以通常實務上也較少會這樣做。

但不管是透過哪一種方式定義函式,呼叫函式的話就直接用「函式名稱(參數)」的方式,像 fn(5); 就可以了。

參考文獻

  1. [https://ithelp.ithome.com.tw/articles/10191549

  2. https://blog.gtwang.org/programming/defining-javascript-functions/

JavaScript 中的「傳值」 與 「傳址」


基本型別

假設我們有兩個變數ab分別設定為 10,接著把b的值等於a;最後再把a的值改為20

1
2
3
4
5
6
7
8
9
var a = 10;
var b = 10;
//在基本型別的時候,會認為這兩個變數的「值」是相等的,因為兩個變數的數值都是 10
console.log( a === b ); // true
a=20;
var c=a;
console.log("a is "+a); // a is 20
console.log("b is "+b); // b is 10
console.log("c is "+c); // c is 10

變數 c 的值是透過複製變數 a 的值而來。

但變數 a 更新之後,不會去影響變數 c 的數值。

表面上看起來變數 c 的內容是透過複製變數 a 而來,但此時若變數 a 的內容為基本型別時,實際上變數 c 是去建立了一個新的值,然後將變數 a 的內容複製了一份過來。

Call By Value

當我們在建立「基本型別」 的變數時,根據上面的例子,a 會存在記憶體中的某個位置。這時候,當我指定另一個變數 c,它的值等同於 a 的時候,c 實際上會建立另一個獨立的記憶體位置,接著再把 a 的值存在這個獨立的記憶體位置。也就是說, a 和 b 其實是存在於兩個不同的記憶體位置,因此彼此並不會乎相干擾影響,這種情況,我們就稱為 Call By Value

物件型別

JavaScript 的物件都應該看作是一個「實體」

1
2
3
4
5
6
7
8
9
10
11
var a= { value: 10 };

var b= { value: 10 };
//// a 與 b 不是同一個實體。
console.log( a === b ); // false

b=a;
a.value=20;
console.log(a.value); // 20
console.log(b.value); // 20
console.log( a === b ); // true

「物件」在 JavaScript 中是透過「引用」的方式傳遞資料的,當 a.value 的內容被更新了之後,連帶著 b.value 也跟著改變。

Call By Reference

當我將變數 a 設立成一個 Object 時,一樣會存在記憶體中的某個位置;但是當我建立一個變數 b,並且把變數 b 的值等同於 a 時,這時候並不會再給予它一個新的位置,而是將 b 指定到物件 a 的位置,讓變數 a 和 b 使用相同的記憶體位置,因此,當 a 的值改變的時候 b 的值也會改變,這種情形我們就稱為 Call By Reference

例外情況

如果使用 object literal 的方式指定物件的值,那麼就會是 Call by value:

1
2
3
4
5
6
7
8
9
var a= { value: 10 };

var b;

b=a;
a={value: 20};

console.log(a); //
console.log(b); //

在這種情況下,因為它並不清楚 a 的內容是已經存在的,所以會建立一個新的記憶體位置來存放 a 物件裡面的內容。

Call by sharing

JavaScript 實際上是另一種稱做「call by sharing」的模式,其特點在於,當 function 的參數,如 function changeValue(obj){ ... } 中的 obj 被重新賦值的時候,外部變數的內容是不會被影響的。

1
2
3
4
5
6
7
8
9
10
11
var a= { value: 10 };


function changeValue(obj) {
obj = { value: 20 };

}

changeValue(a);

console.log(a); // 此時 a仍是 { value: 10 }

如果不是重新賦值的情況,則又會回到傳址的方式:

1
2
3
4
5
6
7
8
9
10
11
12
var a = { value: 10 };


function changeValue(obj) {
// 僅更新 obj.value,並未重新賦值
obj.value = 20;

}

changeValue(a);

console.log(a); // 此時 a 則會變成 { value: 20 }

參考文獻

  1. https://ithelp.ithome.com.tw/articles/10191057

  2. https://pjchender.blogspot.com/2016/03/javascriptby-referenceby-value.html

JavaScript 陣列


陣列

JavaScript 的陣列可以看作是一種特別的「物件」, 陣列內可以是原始的資料類型、其他陣列、函式等等。

建立陣列

陣列可以使用字面表達語法來建立︰

1
var fruits = ['Apple', 'Banana'];

或是使用 Array 的建構子來建立︰

1
2
3
var fruits = new Array();
fruits[0] = "Apple";
fruits[1] = "Banana";

(透過索引)取得陣列項目

1
2
var first = fruits[0]; //Apple
var last = fruits[fruits.length - 1]; // Banana

迭代陣列

1
2
3
4
5
fruits.forEach(function(item, index, array) {
console.log(item, index);
});
// Apple 0
// Banana 1

加入項目至陣列末端

1
2
var newLength = fruits.push('Orange');
// ["Apple", "Banana", "Orange"]

移除陣列末端項目

1
2
var last = fruits.pop(); // 移除 (最末端的) Orange
// ["Apple", "Banana"];

移除陣列前端項目

1
2
var first = fruits.shift(); // 移除 (最前端的) Apple
// ["Banana"];

加入項目至陣列前端

1
2
var newLength = fruits.unshift('Strawberry') // 加到陣列前端
// ["Strawberry", "Banana"];

在陣列中尋找項目的索引

1
2
3
4
5
fruits.push('Mango');
// ["Strawberry", "Banana", "Mango"]

var pos = fruits.indexOf('Banana');
// 1

移除指定索引位置的項目

1
2
3
var removedItem = fruits.splice(pos, 1); // 移除 pos 起的 1 個項目

// ["Strawberry", "Mango"]

移除指定索引位置起的多個項目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var vegetables = ['Cabbage', 'Turnip', 'Radish', 'Carrot'];
console.log(vegetables);
// ["Cabbage", "Turnip", "Radish", "Carrot"]

var pos = 1, n = 2;

var removedItems = vegetables.splice(pos, n);
// 這就是移除項目的方式,
// n 表示從該位置 (pos) 開始,一直到陣列的尾端有多少項目需要移除

console.log(vegetables);
// ["Cabbage", "Carrot"] (原始的陣列被改變)

console.log(removedItems);
// ["Turnip", "Radish"]

複製陣列

1
2
var shallowCopy = fruits.slice(); // 這就是複製陣列的方式
// ["Strawberry", "Mango"]

將陣列元素合併成字串

1
2
3
4
5
6
7
8
9
10
var elements = ['Fire', 'Air', 'Water'];

console.log(elements.join());
// expected output: "Fire,Air,Water"

console.log(elements.join(''));
// expected output: "FireAirWater"

console.log(elements.join('-'));
// expected output: "Fire-Air-Water"

刪除陣列元素

刪除陣列元素後,該元素為undefined。

1
2
3
4
var arr = [1, 2, 3, 4, 5, 6];

delete arr[1];
//[1,undefined,3, 4, 5, 6]

將字串或輸入參數組成陣列

1
2
3
4
5
console.log(Array.from('foo'));
// expected output: Array ["f", "o", "o"]

console.log(Array.from([1, 2, 3], x => x + x));
// expected output: Array [2, 4, 6]

對陣列中的各元素進行操作,操作後的值會被寫入新的陣列中並返回

map 會將所有陣列中的元素依序分別傳入一次至 callback 函式當中,並以此回呼函式每一次被呼叫的回傳值來建構一個新的陣列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var array1 = [1, 4, 9, 16];

// pass a function to map
const map1 = array1.map(x => x * 2);

console.log(map1);
// expected output: Array [2, 8, 18, 32]


var arr = [1, 2, 3, 4, 5, 6];

var arr2 = arr.map(function (element,index,array) {

return element * 2;

});

console.log(arr2);
// [2, 4, 6, 8, 10, 12]

會將兩個陣列合併產生新的陣列,原陣列不改變

concat() 方法被用來合併兩個或多個陣列。此方法不會改變現有的陣列。

1
2
3
4
5
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];

console.log(array1.concat(array2));
// expected output: Array ["a", "b", "c", "d", "e", "f"]

陣列比對(some)

陣列比對,只要有一個元素是 true,就返回 true。

1
2
3
4
5
6
7
8
9
var array = [1, 2, 3, 4, 5];

var even = function(element) {
// checks whether an element is even
return element % 2 === 0;
};

console.log(array.some(even));
// expected output: true

陣列比對(every)

陣列比對,所有元素都是 true 才是 true。

1
2
3
4
5
6
7
8
function isBelowThreshold(currentValue) {
return currentValue < 40;
}

var array1 = [1, 30, 39, 29, 10, 13];

console.log(array1.every(isBelowThreshold));
// expected output: true

陣列過濾

陣列過濾,透過 filter 的過濾條件返回一個新陣列。

1
2
3
4
5
6
var words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);

console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]

檢查傳入的值是否為陣列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 下方都回傳 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
Array.isArray(new Array('a', 'b', 'c', 'd'));
Array.isArray(new Array(3));
// 小細節:Array.prototype 本身是陣列:
Array.isArray(Array.prototype);

// 下方都回傳 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray({ __proto__: Array.prototype });

參考文獻

  1. https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array

  2. https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/map

  3. https://sweeteason.pixnet.net/blog/post/41263148-javascript-%E5%B8%B8%E7%94%A8%E7%9A%84%E9%99%A3%E5%88%97%28array%29%E6%93%8D%E4%BD%9C%E5%A4%A7%E5%85%A8

JavaScript 物件

物件及屬性

所有基本型別 (Primitives) 以外的值都是物件。

一個物件可以是個零至多種屬性的集合,而屬性是鍵 (key) 與值 (value) 之間的關聯。 一個屬性的「值」可以是某個基本型別,也可以是另一個物件,甚至可以是一個函數。

可以透過 new 關鍵字來建立一個物件實體,再替這個物件新增屬性與方法:

例如,我們可以定義一個物件為 myCar ,並賦予三個屬性, makemodelyear

1
2
3
4
var myCar = new Object();
myCar.make = 'Ford';
myCar.model = 'Mustang';
myCar.year = 1969;

或是使用大括號 { } 來建立一個物件,並且在建立物件的同時直接指定屬性至該物件內。

這種建立物件的方式稱為「物件實字 (Object literal)」。

1
2
3
4
5
var myCar = {
make : 'Ford',
model : 'Mustang',
year : 1969
};

屬性存取

物件的屬性可以透過 . 來進行存取:

1
2
3
myCar.make;
myCar.model;
myCar.year;

或是可以透過 [ ] 來進行存取:

1
2
3
myCar['make'];
myCar['model'];
myCar['year'];

存取物件沒有的屬性會顯示 undefined

1
myCar.color; // undefined

新增 / 更新 屬性

新增與更新屬性的語法是一樣的,只需對屬性進行指派值的動作。

1
2
3
myCar["year"]=1995;
myCar["color"]="yellow";
myCar.tire="EDITION";

屬性刪除

透過 delete 關鍵字來刪除,刪除後的屬性會變成 undefined:

1
2
3
4
myCar.color="red";
myCar.color; //red
delete myCar.color;
myCar.color; //undefined

參考文獻

  1. https://ithelp.ithome.com.tw/articles/10190962

  2. https://ithelp.ithome.com.tw/articles/10193605

  3. https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Working_with_Objects

JavaScript 變數與資料型別


變數

變數是用來儲存資料和進行運算的基本單位,就像是資料的容器。

例如下面這個例子,x y z 都是所謂的變數:

1
2
3
var x = 1;
var y = 2;
var z = x + y;

JavaScript 變數的命名有一定規則和限制:

  1. 變數的開頭只能是字母、底線_或錢字號$,後面可以是英文字母、底線_ 或是錢字號 $ 以及數字。
  2. 大小寫有區別,例如變數 test 不等於變數 Test
  3. 變數名稱不可以是保留字,否則會出現 SyntaxError
1
var break = 'test';

Uncaught SyntaxError: Unexpected token 'break'

JavaScript 允許的字母還包含 Unicode,所以中文也可以用作變數名稱,例如:

1
2
var 測試 = 'test';
console.log(測試);

弱型別

相較於JavaC++「強型別」語言,宣告出來的變數無法再被指派為其他型別的值,而JavaScript為「弱型別」語言,其變數擁有以下特性:

  • 變數並沒有綁定任何的型態
  • 變數本身無需宣告型別
  • 宣告後的變數可以被自由指派為其他型別的值

範例

1
2
3
4
var test = 'test';
console.log(test); //"test"
test = 100;
console.log(test); //100

變數無法被刪除

在 JavaScript 中,變數無法被刪除:

1
2
3
4
var test = 'test';
console.log(test); //"test"
delete test;
console.log(test); //"test"

如果是刪除物件的屬性,則刪除後該屬性為 undefined:

1
2
3
4
5
6
7
8
9
10
11
12
var Employee = {
firstname: "John",
lastname: "Doe"
}

console.log(Employee.firstname);
// expected output: "John"

delete Employee.firstname;

console.log(Employee.firstname);
// expected output: undefined

變數的資料型別

變數沒有型別,值才有。

JavaScript 內建的型別主要可以分成基本型別 (Primitives) 與物件型別 (Object) 兩大類:

基本型別:

  • string
  • number
  • boolean
  • null
  • undefined

除了上述幾種之外,都可以歸類至物件型別 (Object)。

判斷型別的方式,可以透過 typeof 運算子。

1
2
3
4
5
console.log(typeof 'test');//  string
console.log(typeof 100);// number
console.log(typeof true);// boolean
console.log(typeof window.alert); // 'function'
console.log(typeof null); // 'object'

雖然透過 typeof 去檢查一個「函式 (function) 」的時候,會得到 “Function” 的結果,但實際上仍屬於 Object 的一種。

而 typeof null 的結果為 Object 。

string

JavaScript 沒有 char (字元) 的概念,只有字串。字串使用 ‘ ‘ (單引號) 或是 “ “ (雙引號) 將文字放入其中,兩者不可混用,意即用單引號開頭的,就要用單引號收合,反過來說也是。 單引號與雙引號的使用在 JavaScript 沒有什麼差異。

特殊符號的處理

要在單引號內包覆單引號,或是雙引號內包覆雙引號就會出現問題:

1
var name = "My name is "Ray"";

Uncaught SyntaxError: Unexpected identifier

可以在符號前加上 \ (跳脫字元)來解決。

1
2
var name = "My name is \"Ray\"";
console.log(name);//My name is "Ray"

字串內容斷行

多行字串時,可以透過 \ (反斜線) 來繼續:

1
2
3
4
var test = '這次\
連假\
要出去玩';
console.log(test);//這次連假要出去玩

請注意 \ 反斜線後面不能有任何字元

number

整數或帶有小數點的數字都是數值型別
另外還有幾種特殊的數字:

  • Infinity (無限大)
  • Infinity (負無限大)
  • NaN (不是數值,Not a Number)。

boolean

值只有兩種:true 以及 false,布林值通常用在判斷式,作為控制程式流程的用途。

Null

null 在 JavaScript 中表示一個空值,變數要經過宣告並賦予 null ,才會形成 null 型態。

1
var test = null;

undefined

變數在初始的時候未給予任何值,宣告 test 時因為沒有賦予任何值所以是 undefined,如果先定義 test 為 100 ; 接著再把 test 設為 undefined,我們會發現 test 又再次變成了undefined了。

1
2
3
4
5
6
7
var test; 
console.log(test);//undefined
test=100;
test=undefined;
if(test===undefined){
console.log("test is undefined.");
}

參考文獻

  1. https://ithelp.ithome.com.tw/articles/10190873

如何在 Visual Studio Code 撰寫 Markdown

本篇介紹如何於Visual Studio Code中安裝Markdown插件。

  • 點擊Extension圖示(或是按下ctrl+shift+X)
  • 在搜尋欄位輸入 Markdown 搜尋套件
  • 點擊 install 按鈕安裝

安裝常用的Markdown優化:

很多人用Markdown是為了最後上傳到Github Pages,所以安裝這個套件,就能在本地預覽Markdown文件最終在Github Pages中的渲染樣式。

  • 點擊zh-TW後重啟Visual Studio Code
  • 完成繁體中文語系設定

參考文獻

  1. https://medium.com/mr-brown/ide-visual-studio-code-%E4%B8%AD%E6%96%87%E5%8C%96%E6%95%99%E5%AD%B8-ff0abd789608

變更 Visual Studio Code 介面語系為中文

本篇介紹如何修改Visual Studio Code為繁體中文,其他不同語系修改方式皆相同,只要安裝不同語系插件即可。

  • 點擊Extension圖示(或是按下ctrl+shift+X)
  • 在搜尋欄位輸入 Chinese(Traditional)搜尋中文化套件
  • 點擊 install 按鈕安裝
  • 安裝完成後按下快捷鍵ctrl+shift+p開啟搜尋列
  • 輸入Configure Display Language
  • 開啟 locale.json 檔進行設定
  • 把 “locale”:”en” 的 en 改成 zh-TW 後存檔
  • 重啟Visual Studio Code
  • 完成繁體中文語系設定

參考文獻

  1. https://medium.com/mr-brown/ide-visual-studio-code-%E4%B8%AD%E6%96%87%E5%8C%96%E6%95%99%E5%AD%B8-ff0abd789608

使用 HTML+CSS 製作簡易名片

程式碼同步於此連結:
使用 HTML+CSS 製作簡易名片

使用*{ }選取器取消網頁所有物件的間距為0:

1
2
3
4
5
* {
font-family : 微軟正黑體;
margin: 0;
padding: 0;
}

為了使div元素的height為整個瀏覽器窗口高度,需先將其父元素設定為100%,這樣子元素高度才會起作用,也就是width:100%; height:100%;

1
2
3
4
html,body{
width : 100%;
height : 100%;
}

延伸閱讀:
為什麼 height:100% 沒有作用?

設定背景為綠色,頁面最上和最下留30px的黑邊;使用box-sizing屬性來讓元素的內距和邊框不會增加元素本身的寬度:

CSS

1
2
3
4
5
6
body{
background-color : #A9CEAE;
border-top : solid 30px #3B3E3C;
border-bottom : solid 30px #3B3E3C;
box-sizing : border-box;
}

HTML

1
2
3
4
<body>
<div class="mark">NEVER<br> &nbsp&nbsp&nbsp&nbsp&nbspSTOP
</div>
</body>

CSS

以下是包含各個元素的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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
.mark {
font-size: 230px;
position: absolute;
}

.namecard {
width: 500px;
height: 300px;
border-radius: 15px 5px 5px 15px;
margin: auto;
margin-top: 100px;
padding-left: 100px;
background-color: #3B3E3C;
color: white;
letter-spacing: 1px;
box-shadow: 25px 25px 15px -20px rgba(0, 0, 0, 0.5);
position: relative;
}

.namecard h2 {
font-size: 30px;
}

.namecard h2 span {
font-size: 17px;
font-weight: 300;
}

.namecard h5 {
font-size: 15px;
letter-spacing: 1px;
font-weight: 300;
}

.namecard p {
font-size: 15px;
font-weight: 300;
}

.hr1 {
border: 2px solid gray;
box-shadow: 0px 2px 5px black;
}

.gap {
width: 35px;
height: 240px;
right: 540px;
top: 30px;
position: absolute;
background-color: #A9CEAE;
border-radius: 15px 0px 0px 15px;
box-shadow: inset 25px 20px 20px -20px rgba(0, 0, 0, 0.5);
}

.vline {
position: absolute;
height: 299px;
right: 520px;
border: solid 2px gray;
}

.screw {
border: solid 2px gray;
border-radius: 100%;
position: absolute;
width: 10px;
height: 10px;
/* background-color : gray; */
}

.screw1 {
right: 500px;
top: 15px;
}

.screw2 {
right: 500px;
top: 280px;
}

h5,h2,p 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
h5 {
display: block;
font-size: 0.83em;
margin-block-start: 1.67em;
margin-block-end: 1.67em;
margin-inline-start: 0px;
margin-inline-end: 0px;
font-weight: bold;
}

h2 {
display: block;
font-size: 1.5em;
margin-block-start: 0.83em;
margin-block-end: 0.83em;
margin-inline-start: 0px;
margin-inline-end: 0px;
font-weight: bold;
}

p {
display: block;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0px;
margin-inline-end: 0px;
}

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body>
<div class="mark">NEVER<br> &nbsp&nbsp&nbsp&nbsp&nbspSTOP
</div>
<div class="namecard">
<div class="gap"></div>
<div class="vline"></div>
<div class="screw screw1"></div>
<div class="screw screw2"></div>
</br>
<h2>鄭亦渟
<span>Cheng Yi Ting</span>
</h2>
<h5>國立中正大學-資訊工程學系</h5>
<hr class="hr1" />
<p>"Opportunity seldom knocks twice."<br>Love to try anything I haven't experienced.</p>
</div>
</body>

為什麼 height:100 沒有作用?

設定 height:100% 元素沒反應!?

當設計一個頁面的時候,你設置了一個div元素,希望元素能佔滿整個瀏覽器窗口,最自然的做法,你會給這個div添加 width:100px; height:100px; 的css屬性。然後你會發現,這個元素的寬度會擴展到整個瀏覽器窗口,但是高度卻沒有起任何作用,那為什麼height:100%會無法作用呢?

按照常理推斷,當我們用CSS的height屬性定義一個元素的高度時,這個元素應該要按照設定在瀏覽器的縱向空間裡擴展相應的空間距離,例如:一個div元素的height為100px;,那它應該在頁面的豎向空間裡佔滿100px的高度才對。

根據W3C的規範,百分比的高度在設定時需要根據這個元素的父元素容器的高度。所以,如果你把一個div的高度設定為height:50%;,而它的父元素的高度是100px時,那麼,這個div的高度應該是50px。

瀏覽器寬度和高度

瀏覽器在計算寬度時會考慮瀏覽器窗口的打開寬度。如果不給寬度設定任何值,那瀏覽器會自動將頁面內容填滿整個橫向寬度。

但是高度的計算方式完全不一樣。事實上,瀏覽器根本就不計算內容的高度,除非內容超出了視窗範圍(導致滾動條出現);否則,瀏覽器就會簡單的讓內容往下堆砌,頁面的高度根本就無需考慮。

當你讓一個元素的高度設定為百分比高度時,無法根據獲取父元素的高度,也就無法計算自己的高度,所以瀏覽器不會對這個值有任何的反應。

範例

設定元素 width:100px; height:100px;

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<body>
<div style="width:100%;height:100%;background-color:green;">
<p>
元素設定高度為100%
</p>
</div>
</body>
</html>

現在你給了這個div的高度為100%,它有兩個父元素 <body> <html> ;為了讓div的百分比高度起作用,需要設定這兩個屬性的高度。

1
2
3
4
5
6
7
8
9
<!DOCTYPE html style="height:100%">
<body style="height:100%">
<div style="width:100%;height:100%;background-color:green;">
<p>
元素設定高度為100%
</p>
</div>
</body>
</html>

從這個範例中你可以發現, height:100%; 生效了

參考文獻

  1. http://www.webhek.com/post/css-100-percent-height.html
  2. https://segmentfault.com/a/1190000012707337