[Công nghệ Thông tin] -- [Web] -- [Công nghệ phần mềm] -- [PhoThong] -- [Đăng ký các khóa học] -- [Langbiang's Portfolio] -- [Học viên cũ] -- [10.000 giờ]
--------------- <> -----------------
---  KHOA HỌC - CÔNG NGHỆ - GIÁO DỤC - VIỆC LÀM --->>>  CÁC KHÓA HỌC...
---  Nhận làm website, web app, chạy quảng cáo, digital marketing --->>>  LIÊN HỆ...

Tìm kiếm trong Blog

Web (1) - Lời nói đầu - Tự học làm web

Lời nói đầu - Tự học làm web

[Xem video]

Câu hỏi đầu tiên xuất hiện trong đầu, khi bạn thực sự muốn bước chân vào lĩnh vực làm web là “muốn theo nghề làm web bắt đầu từ đâu?”.

Thực tế, bạn có thể bắt đầu theo nhiều cách, ví dụ:

– Cách một, học bài bản theo chương trình của một trường đại học, cao đẳng, hay trung tâm (tạm gọi là chương trình chính quy)

– Cách hai, tự học bằng cách kết hợp các chỉ dẫn, các bài học của rất nhiều thầy cô, anh chị trên mạng; cùng với các khóa học trực tuyến của các công ty, tổ chức, và cá nhân. Tạm gọi cách học thứ 2 này là học theo chương trình tự chế ––tự các bạn chế ra.

Học bài bản theo chương trình chính quy có một số đặc điểm sau:

– Bạn phải vượt qua được các kì thi đầu vào, các đợt xét tuyển của các trường đại học và cao đẳng

– Học theo chương trình được thiết kế sẵn của các trường

– Chương trình học khá bài bản và chi tiết, cho phép bạn có thể lựa chọn và theo đuổi nhiều ngành nghề khác nhau

– Bạn cần phải chi trả một khoản tiền khá lớn cho học phí, học liệu, ăn ở, và đi lại

– Cần thời gian khá dài theo đúng tiến độ đào tạo của các trường

– Có nhiều môn học khó; không phải là thế mạnh của bạn; hoặc bạn không thích, nhưng vẫn phải học

Trong phần tiếp theo (phần Tổng quan) sẽ trình bày cụ thể hơn về lộ trình học theo chương trình chính quy, để bạn có thêm một góc nhìn.

Tuy nhiên, nếu bạn không có nhiều tiền, nhưng có ý chí và muốn có một cái nghề; hoặc đơn giản bạn muốn tự tìm kiếm cho mình một con đường đi riêng thì bạn vẫn hoàn toàn có thế học được nghề làm web theo chương trình tự chế.

Để học theo chương trình tự chế, bạn cần phải chuẩn bị một cái máy tính; một ít chi phí để mua các khóa học, tài liệu; nếu tính toán hợp lý, thì chi phí này bằng khoảng một tháng lương thử việc của các bạn lập trình viên. Chi phí lớn nhất chính là thời gian, ý chí và quyết tâm của bạn. Tài liệu này được viết cho các bạn học theo kiểu tự chế. Mời bạn cùng trải nghiệm.

Để có thể làm web, bạn cần đạt được các điều sau:

– Nắm được các kiến thức cơ bản, cần thiết, để tạo ra sản phẩm; làm cơ sở giúp bạn học được các chủ đề nâng cao

– Học kiến thức một cách bài bản, có “lớp lang”, để trả lời được các câu hỏi “tại sao lại làm như thế?”. Thực tế có nhiều bạn biết làm nhưng không biết tại sao lại làm như vậy.

– Kỹ năng làm ra sản phẩm, làm nhiều thì sẽ quen, làm các sản phẩm từ dễ đến khó

– Kỹ năng tự học, tự đọc tài liệu (tiếng Việt, Anh) để có kiến thức áp dụng vào thực tế

– Thái độ đúng đắn khi làm nghề: yêu nghề, có đạo đức nghề nghiệp, tính kỉ luật, tinh thần trách nhiệm, khiêm tốn, không ngừng học hỏi

 “TỰ HỌC LÀM WEB, Tập 1 – HTML” là cuốn sách đầu tiên trong loạt các bài học giúp bạn có thể tự tin bước vào nghề. Sách được viết theo kiểu dẫn dắt từng bước, bắt đầu với các kiến thức lý thuyết căn bản, đây được xem như những viên gạch nền móng, từ đó người học sẽ dễ dàng tiếp cận các kiến thức sâu hơn, khó hơn; tiếp đến có thể tự tìm tòi và thử nghiệm kiến thức đã biết vào việc tạo ra sản phẩm.

Tiếp sau phần kiến thức căn bản, tài liệu cũng cung cấp các từ khóa, liên kết tới các trang web, sách điện tử (ebook), và video khác trên mạng để bạn tự tìm hiểu, tự thực hành thêm, giúp bạn có thêm nhiều góc nhìn, nhiều thông tin và nhiều trải nghiệm hơn. Sau khi đã có những hiểu biết cơ bản về một chủ đề, tài liệu sẽ cung cấp các bài tập và bài thực hành nhằm giúp người đọc hiểu rõ hơn lý thuyết, từng bước nâng cao kỹ năng thực hành, có thể tạo ra các sản phẩm.

Ngoài ra, sách cũng có các bài tập, câu hỏi bằng tiếng Anh, giúp người đọc từng bước làm quen, để tiến tới sẽ đọc và làm việc với các tài liệu hoàn toàn bằng tiếng Anh. Bạn có thể sử dụng danh mục các từ tiếng Anh chuyên ngành tại đây: https://bit.ly/3iLYpgG.

Cuối mỗi phần sẽ có các câu hỏi trắc nghiệm, giúp người học hệ thống và củng cố lại kiến thức. Các bạn cũng sẽ tìm thấy liên kết đến các video bài giảng, hướng dẫn làm bài tập và thực hành ứng với mỗi chủ đề trên Youtube.

Nội dung của cuốn sách này:

– Giới thiệu một số chủ đề về chọn nghề, học làm nghề và phương pháp học

– Kiến thức căn bản về web, trình duyệt, URL, siêu liên kết, siêu văn bản

– Kiến thức tổng quan về HTML

– Cách hiển thị văn bản

– Tìm hiểu về liên kết

– Hiển thị hình ảnh

– Thiết kế form

– Nhúng nội dung vào trang web

– Các chủ đề mở rộng liên quan đến HTML.

Đây là cuốn sách đầu tiên trong loạt các cuốn sách tự học làm web. Cuốn sách tiếp theo bạn nên có là “TỰ HỌC LÀM WEB, Tập 2 – CSS”.

Dù đã cố gắng, nhưng tài liệu này chắc chắn còn hạn chế về kiến thức, kĩ năng, nhận định. Mong bạn luôn đọc trong tâm thế hoài nghi.

[Xem video]

-------

Cập nhật: 3/1/2024
-------
Tải tài liệu đầy đủ: Tự học HTML
------

Web back-end (8) - Một số chủ đề JavaScript (1)

Bài trước: Web back-end (7) - Local và Global, Dependencies và devDependencies

-----

8. Một số chủ đề JavaScript (1)

Chúng ta cùng quay trở lại ứng dụng web TeoShop.

Quan sát tập tin mã nguồn của index.js.

[index.js]

'use strict'

const express = require('express')

const app = express();

const port = process.env.PORT || 9000

 

// xu ly khi nguoi dung gui request toi web server

app.get("/", (req, res) => {

    res.send('Chao ban den voi TeoShop!');

})

// khoi dong web server

app.listen(port, () => {

    console.log(`server dang chay tren cong ${port}`);

})

Để hiểu được mã JavaScript trong tập tin index.js và có kiến thức để lập trình các phần tiếp theo, chúng ta cùng tìm hiểu một số chủ đề về lập trình JavaScript.

8.1 Lập trình đồng bộ trong JavaScript

Chúng ta sẽ bắt đầu với khái niệm lập trình đồng bộ.

Trong JavaScript, lập trình đồng bộ (synchronous programming) là kỹ thuật lập trình mà các lệnh (statements) được thực thi tuần tự, theo thứ tự từ trên xuống dưới. Mỗi lệnh phải hoàn thành trước khi lệnh tiếp theo được thực thi. Điều này có nghĩa là nếu một tác vụ mất nhiều thời gian (như đọc tập tin, gọi API, giao tiếp client-server), thì toàn bộ chương trình sẽ bị "chặn" (blocked) cho đến khi tác vụ đó hoàn tất.

Đặc điểm của lập trình đồng bộ

- Thứ tự thực thi rõ ràng: các lệnh chạy theo thứ tự được viết trong mã nguồn

- Chặn luồng (blocking): một lệnh chưa xong thì lệnh tiếp theo không thể chạy

- Phù hợp với tác vụ đơn giản: các tác vụ không cần chờ đợi (như tính toán cơ bản) thường được xử lý đồng bộ

Chúng ta cùng lập trình và quan sát một số ví dụ

Ví dụ 1. Một tính toán căn bản

- Tạo tập tin tinhToanCanBan.js bằng phần mềm viết mã bất kỳ

- Nhập vào đoạn mã sau

[tinhToanCanBan.js]

function cong(a, b) {

    return a + b;

}

 

console.log("Bắt đầu");

let kq = cong(6,8); // thực thi đồng bộ

console.log("Kết quả:", kq);

console.log("Kết thúc");

Mở cửa sổ dòng lệnh, sử dụng node để chạy tập tin tinhToanCanBan.js.

E:\TeoShop_Test\bat-dong-bo>node tinhToanCanBan.js

Bắt đầu

Kết quả: 14

Kết thúc

Bạn sẽ thấy các lệnh chạy theo thứ tự: in chữ "Bắt đầu" ra màn hình > tính cong(6, 8) > in "Kết quả: 14" > rồi in "Kết thúc". Không có hiện tượng xáo trộn các lệnh khi thực thi, mọi thứ diễn ra tuần tự.

Ví dụ 2. Vòng lặp đồng bộ

[vongLap.js]

function xuLyDaySo(){

    console.log("Bắt đầu xử lý ...");

    for(let i = 1; i <= 5; i++){

        console.log("Số:", i);

    }

    console.log("Xử lý xong!");

}

 

xuLyDaySo();

console.log("Tiếp tục công việc khác");

Kết quả khi chạy:

E:\TeoShop_Test\bat-dong-bo>node vongLap.js

Bắt đầu xử lý ...

Số: 1

Số: 2

Số: 3

Số: 4

Số: 5

Xử lý xong!

Tiếp tục công việc khác

Bạn sẽ thấy: vòng lặp for chạy đồng bộ: in từng số, từ 1 đến 5 trước khi tiếp tục công việc khác. Chỉ khi hàm xuLyDaySo() hoàn tất, dòng "Tiếp tục công việc khác" mới được in.

Ví dụ 3. Giả lập tác vụ có tình huống chặn luồng chương trình (khóa chương trình) (blocking)

[chanLuong.js]

// chặn luồng

function chanLuong(){

    console.log("Bắt đầu tác vụ cần nhiều thời gian xử lý");

    let batDau = Date.now();

    while(Date.now() - batDau < 5000){

        // Giả lập chờ 5 giây bằng vòng lặp

    }

    console.log("Tác vụ chạy 5 giây hoàn tất")

}

 

console.log("Trước khi chạy tác vụ");

chanLuong() // chặn luồng 5 giây

console.log("Sau khi chạy tác vụ");

Kết quả khi chạy:

E:\TeoShop_Test\bat-dong-bo>node chanLuong.js

Trước khi chạy tác vụ

Bắt đầu tác vụ cần nhiều thời gian xử lý

Tác vụ chạy 5 giây hoàn tất

Sau khi chạy tác vụ

Bạn sẽ thấy: hàm chanLuong() giả lập một tác vụ mất 5 giây bằng cách chặn luồng. Dòng thông báo "Sau khi chạy tác vụ" chỉ được in, sau khi chayLuong() hoàn tất, vì mọi thứ chạy đồng bộ, mặc dù chương trình dừng lại rất lâu nhưng không có xử lý khác được chèn vào.

8.2 Hàm ẩn danh

Hàm ẩn danh (anonymous function) là một hàm không có tên (không được đặt tên) khi định nghĩa. Thay vì khai báo với từ khóa function đi kèm với tên như hàm thông thường, hàm ẩn danh thường được gán trực tiếp vào biến, truyền làm tham số, hoặc thực thi ngay lập tức mà không cần gọi hàm.

Đặc điểm của hàm ẩn danh:

- Không có tên: được định nghĩa mà không cần đặt tên sau từ khóa function

- Tính linh hoạt: thường được dùng ngay tại nơi khai báo hoặc gán vào biến

- Phạm vi: có thể truy cập biến trong phạm vi bao quanh (closure)

- Không hoisting: không được "nâng lên" (hoisted) như hàm khai báo (function declaration)

Hàm ẩn danh được dùng để xử lý các tác vụ ngắn gọn, trong callback, sự kiện, hoặc khi không cần tái sử dụng hàm.

Cú pháp

Hàm ẩn danh thông thường:

function() {

// thân hàm

}

Hàm ẩn danh kiểu mũi tên:

() => {

// thân hàm

}

Một số ví dụ về cách dùng hàm ẩn danh

Ví dụ 1: gán hàm ẩn danh cho một biến. Vì JavaScript coi hàm cũng là đối tượng, nên bạn có thể dùng biến để chứa nội dung của hàm.

const cong = function(x,y){

    return x + y;

}

 

console.log(cong(2,4)); //6

Hàm ẩn danh function(x,y) được gán vào biến cong. Sau đó được gọi thực thi như một hàm thông thường.

Ví dụ 2: dùng hàm ẩn danh như là tham số để truyền vào hàm khác (callback)

setTimeout(function() {

    console.log("Đã hết 3 giây! (sau 3 giây)");

}, 3000);

 

console.log("Đang chờ");

Kết quả chạy:

Đang chờ

Đã hết 3 giây! (sau 3 giây)

Ví dụ 3: định nghĩa hàm ẩn danh bằng cú pháp mũi tên (arrow function)

setTimeout(() => {

    console.log("Đã hết 4 giây! (sau 4 giây)");

}, 4000);

console.log("Đang chờ");

Kết quả chạy:

Đang chờ

Đã hết 4 giây! (sau 4 giây)

Ví dụ 4: sử dụng trong phương thức của mảng. Hàm ẩn danh được dùng làm tham số, để truyền cho phương thức của mảng.

const numbers = [1, 2, 3, 4];

numbers.forEach(function(num) {

    console.log(num + 1);

});

// Kết quả: 2, 3, 4, 5

Viết lại theo kiểu arrow function:

const numbers = [1, 2, 3, 4];

numbers.forEach(num => console.log(num + 1));

// Kết quả: 2, 3, 4, 5

Ví dụ 5: hàm ẩn danh có thể thực thi ngay sau khi định nghĩa. (Immediately Invoked Function Expression - IIFE).

Cú pháp:

(function() { ... })()

Ví dụ:

(function() {

    console.log("Hàm chạy ngay sau khi định nghĩa, không cần thao tác gọi hàm!");

})();

Tuy nhiên, hàm ẩn danh cũng có một số hạn chế như:

- Khó gỡ lỗi (debug); vì không có tên, việc xác định lỗi trong stack trace có thể khó khăn hơn.

- Không tái sử dụng được: nếu cần dùng lại, bạn phải gán nó cho một biến hoặc đặt tên

8.3 Bài tập

Bài tập 8.1 Cài đặt các ví dụ trong bài học.

Câu 8.2: Lập trình đồng bộ trong JavaScript là gì? Phát biểu nào sau đây không đúng?

A. Lập trình đồng bộ không chặn luồng, cho phép các lệnh tiếp theo chạy ngay cả khi tác vụ chưa hoàn tất.

B. Các lệnh được thực thi tuần tự, theo thứ tự từ trên xuống dưới.

C. Mỗi lệnh phải hoàn thành trước khi lệnh tiếp theo được thực thi.

D. Phù hợp với các tác vụ đơn giản như tính toán cơ bản không cần chờ đợi.

Câu 8.3: Hàm ẩn danh (anonymous function) trong JavaScript là gì? Phát biểu nào sau đây không đúng?

A. Hàm ẩn danh có thể truy cập biến trong phạm vi bao quanh nhờ closure.

B. Hàm ẩn danh là hàm không có tên khi được định nghĩa.

C. Hàm ẩn danh thường được gán vào biến hoặc truyền làm tham số cho hàm khác.

D. Hàm ẩn danh được "nâng lên" (hoisted) giống như hàm khai báo (function declaration).

-----

Cập nhật: 10/3/2025

-----

Bài sau: Web back-end (9) - Một số chủ đề JavaScript (2)

Web front-end (9) - HTML - Một số phần tử HTML khác

Bài trước: Web front-end (8) - HTML - Phần mềm lập trình web

-------

Xem video bài giảng

1.1       Một số phần tử HTML khác

1.1.1       Các phần tử inline

Ở những phần trước, bạn đã tìm hiểu cách hiển thị các khối dữ liệu lớn (chunk), gồm các phần tử tạo bố cục, và các phần tử kiểu khối (block). Phần này, bạn sẽ tiếp tục tìm hiểu cách hiển thị các nội dung nhỏ hơn, bằng các phần tử có kiểu hiển thị nội tuyến, trong hàng (inline).

Bảng sau liệt kê các phần tử và chức năng của chúng,

Phần tử (thẻ)

Mô tả

<a>

Tạo siêu liên kết (hyperlink). Ví dụ,

<a href="https://stackoverflow.com/">Stack Overflow</a>

<abbr>

Tạo chú thích cho các chữ viết tắt (abbreviation). Phần tử này cung cấp thông tin cho trình duyệt, máy tìm kiếm, hệ thống dịch. Nội dung chú thích chính là giá trị của thuộc tính title. Ví dụ,

<p><abbr title="World Health Organization">WHO</abbr> được thành lập năm 1948</p>

<b>

Thêm tính trực quan, gây chú ý tới dữ liệu (bôi đậm), ví dụ các từ khóa

<p>C++ là ngôn ngữ lập trình kiểu <b>biên dịch</b></p>

<bdi>

Làm cho hướng (direction) của văn bản sẽ ngược lại với phần tử bao ngoài nó. Phần tử này hữu ích khi không xác định được hướng của văn bản do người dùng tạo ra. bdi là viết tắt của Bi-Directional Isolation.

<bdo>

Dùng để thay đổi hướng (direction) của văn bản (viết từ phải sang trái, hoặc viết từ trái sang phải). bdo là viết tắt của Bi-Directional Override. Phần tử này được sử dụng trong các trang web đa ngôn ngữ, khi có ngôn ngữ được viết theo hướng từ phải sang trái. Ví dụ,

<p>Hàng này được viết từ trái sang phải</p>

<p><bdo dir="rtl">Hàng này được viết từ phải sang trái</bdo></p>

<br>

Xuống hàng (br – break)

<cite>

Dùng để chứa tên của một sản phẩm (title of a work), như tên của một cuốn sách, một bộ phim, một bức tranh…v.v. Ví dụ,

<p><cite>Scream</cite> là bức tranh Edward Munch vẽ vào năm 1893</p>

<code>

Dùng để chứa phần mã nguồn của một ngôn ngữ lập trình. Mã nguồn sẽ được hiển thị ở dạng phông chữ monospaced (các kí tự có độ rộng bằng nhau). Ví dụ,

<p>Khai báo biến namSinh <code>int namSinh;</code> ở phần đầu chương trình</p>

<del>

Dùng để định nghĩa một văn bản bị xóa khỏi văn bản gốc (deleted). Về mặt hình thức, văn bản bị xóa sẽ được gạch ngang. Ví dụ,

<p>Cho tôi một ly <del>ca cao</del> <ins>trà</ins></p>

<dfn>

Dùng để định nghĩa một thuật ngữ khi nó xuất hiện lần đầu trong tài liệu (definition).

Lưu ý: phần tử cha gần nhất phải chứa định nghĩa/giải thích cho thuật ngữ trong phần tử dfn. Phần tử p trong ví dụ dưới đây chính là phần tử cha gần nhất.

<p><dfn>HTML</dfn> là ngôn ngữ đánh dấu siêu văn bản</p>

<em>

Dùng để tạo ra văn bản cần nhấn mạnh khi phát âm (emphasized). Ví dụ,

<p>You <em>have</em> to hurry up!</p>

<i>

Xác định phần văn bản có giọng đọc hoặc tâm trạng khác so với văn bản xung quanh, chỉ ra một thuật ngữ, một đoạn trích từ ngôn ngữ khác. Nội dung trong thẻ này thường được in nghiêng

<p><i>HMTL</i>là ngôn ngữ đánh dấu siêu văn bản</p>

<ins>

Dùng để định nghĩa nội dung được thêm vào văn bản gốc (inserted). Về mặt hình thức, nội dung thêm vào sẽ được gạch chân. Ví dụ,

<p>Cho tôi một ly <del>ca cao</del> <ins>trà</ins></p>

<kbd>

Dùng để hiển thị nội dung người dùng sẽ nhập từ bàn phím (keyboard). Ví dụ,

<p>Nhập địa chỉ IP: <kbd>192.168.1.1</kbd></p>

<mark>

Tạo tính trực quan cho văn bản có liên quan. Văn bản sẽ được tô màu. Ví dụ,

<p><mark>Cụm từ này</mark> đã được nhắc đến ở phía trên<p>

<q>

Dùng để chứa nội dung trích dẫn (ngắn), thường là một cụm từ. Khi hiển thị, trình duyệt sẽ bao nội dung trích dẫn bằng dấu nháy kép (“”). q là viết tắt của quote. Ví dụ,

<p>Theo Wiki: <q>HTML là ngôn ngữ đánh dấu siêu văn bản</q></p>

<s>

Dùng để đánh dấu một nội dung không còn đúng nữa. Ví dụ,

<p><s>Cu Tèo thích mặc áo xanh</s></p>

<p>Hôm nay, Cu Tèo thích mặc áo đỏ</p>

<samp>

Dùng để định dạng kết quả do máy tính xuất ra (sample). Ví dụ,

<p>Chương trình sẽ xuất ra kết quả là: <samp>xin chào</samp></p>

<small>

Dùng để viết văn bản nhỏ hơn bình thường. Ví dụ,

<p>Chữ <small>này</small> sẽ được viết nhỏ hơn bình thường </p>

<span>

Dùng để nhóm một phần của câu/đoạn. Chữ span có nghĩa là khoảng nhỏ. Ví dụ,

<p>Chỉ có chữ <span style="color:red">này</span> có màu đỏ thôi</p>

<strong>

Dùng để tạo ra văn bản có tính chất quan trọng (strong). Ví dụ,

<p>Đây là nội dung <strong>quan trọng</strong></p>

<sub>

Dùng để viết chữ hoặc số thấp hơn dòng chữ bình thường (subscript). Ví dụ,

<p>Số 2 sẽ được viết thấp hơn dòng chữ bình thường H<sub>2</sub>O</p>

<sup>

Dùng để viết chữ hoặc số cao hơn dòng chữ bình thường (superscript). Ví dụ,

<p>Số 2 sẽ được viết cao hơn dòng chữ bình thường x<sup>2</sup></p>

<time>

Dùng để chứa thông tin về thời gian, giúp máy có thể đọc được. Ví dụ,

<p>Giờ mở cửa là: <time datetime="22:00">10:00p.m</time> </p>

<u>

Báo văn bản bị sai chính tả, phần văn bản sẽ được gạch chân (underline). Ví dụ,

<p>Chữ <u>này</u>bị sai chính tả</p>

<var>

Được dùng để định nghĩa một biến (variable), thường được sử dụng cùng với thẻ <pre> và thẻ <code>. Ví dụ,

<p><code>document.write("<var>user-name</var>")</code></p>

<wbr>

Được dùng để ngắt dòng có kiểm soát. Ví dụ, có một từ dài, nếu không muốn trình duyệt ngắt dòng một cách ngẫu nhiên theo kích thước màn hình, thì sử dụng phần tử này. Ví dụ,

<p>Đây là một từ rất dàidàidàidàidàidàidàidàidàidài dàidàidàidàidàidàidàidàidàidàidàidàidàidàidàidàidàidàidàidài<wbr>nósẽbịngắttại<wbr>cácvịtrícụthểkhicửasổtrìnhduyệtthayđổikíchthước.</p>

1.1.2       Div và span

Mặc dù HTML có rất nhiều loại phần tử khác nhau, tuy nhiên, thực tế vốn đa dạng, do vậy sẽ có nhiều trường hợp không thể tìm được phần tử HTML thực sự có ngữ nghĩa để biểu diễn được nội dung. Để xử lý tình huống này, HTML đưa ra hai phần tử trung tính (generic element) là divspan.

Phần tử trung tính là phần tử không có ngữ nghĩa cụ thể, tuy vậy, ngữ nghĩa của các phần tử này sẽ được xác định nhờ hai thuộc tính (attribute) đi kèm là classid. Đây là ưu điểm rất lớn của phần tử trung tính, nó cho phép người lập trình có thể tạo ra rất nhiều các phần tử khác nhau để biểu diễn dữ liệu, định dạng và xử lý tương tác.

Phần tử div

div là phần tử trung tính, nên bạn có thể dùng nó để nhóm các phần tử kiểu inline và block khác, mà không cần quan tâm tới khía cạnh ngữ nghĩa. Div là viết tắt của division (phân chia, phân vùng). Ngữ nghĩa của mỗi phần tử div sẽ được xác định bằng giá trị của thuộc tính id hoặc class đi kèm. Nhờ thuộc tính idclass, bạn có thể thực hiện định dạng phần tử div bằng CSS, xử lý tương tác bằng JavaScript một cách dễ dàng. Phần tử div được hiển thị theo kiểu block.

Ví dụ, dùng div để nhóm nội dung,

<div class="cv">

                        <img src="anh-ung-vien.gif" alt="ảnh ứng viên">

                        <p>Nội dung cv</p>

            </div>

Ví dụ, dùng div để tạo bố cục của một trang,

<div id="tin-tuc">

                        <h1>Tin tức tuần qua</h1>

                        <p>Nội dung tin</p>

            </div>

            <div id="gia-vang">

                        <h1>Giá vàng tuần qua</h1>

                        <p>Bảng giá vàng</p>

            </div>

Lưu ý, trong mọi trường hợp, nên ưu tiên sử dụng các phần tử có ngữ nghĩa khi viết mã HTML, nếu không thể chọn được phần tử phù hợp, thì mới dùng đến phần tử div.

Phần tử span

Cũng có chức năng tương tự như div, chỉ khác là div là một phần tử kiểu khối, trong khi span là phần tử kiểu nội tuyến. Nghĩa là, nếu muốn nhóm những thứ như một từ, một cụm từ hoặc một đối tượng nội tuyến khác thì sử dụng phần tử trung tính span. Span nghĩa là một gang tay, hiểu là một đoạn nhỏ.

Ví dụ, để định dạng các số điện thoại, sử dụng phần tử span để chứa số điện thoại, gán cho phần tử span này một cái tên, ví dụ là tel (bằng thuộc tính class), vậy là có thể định dạng các số điện thoại bằng CSS và lập trình tương tác bằng JavaScript.

<ul>

<li>Tèo: <span class="tel">6677.0028</span></li>

<li>Tí: <span class="tel">5508.0808</span></li>

<li>Mít: <span class="tel">6677.5508</span></li>

<li>Khoai: <span class="tel">0909.3509</span></li>

</ul>

Thuộc tính id và class

Nhắc lại một chút, thuộc tính (attribute) là thành phần bổ sung của mỗi phần tử HTML. Thuộc tính được dùng để thay đổi chức năng mặc định của phần tử hoặc là một thành tố bắt buộc phải có, để một phần tử có thể thực hiện đúng chức năng.

Ở đây, hai thuộc tính idclass sẽ được dùng để thay đổi chức năng mặc định của phần tử. Vậy thay đổi bằng cách nào? Idclass được gọi là các thuộc tính phổ dụng (standard attributes, global attributes), nghĩa là nó có thể gắn vào hầu hết các phần tử HTML. Idclass được dùng để định danh (identification), để xác định tính duy nhất của một phần tử (id) hoặc một nhóm phần tử (class). Khi phần tử hoặc nhóm phần tử đã được xác định rồi, thì người lập trình có thể thực hiện định dạng bằng CSS và xử lý tương tác với nó bằng JavaScript.

Để xác định tính duy nhất của một phần tử, thì sử dụng thuộc tính id. Id viết tắt của identify, nghĩa là định danh.

Để xác định một nhóm các phần tử, thì sử dụng thuộc tính class. Class là viết tắt của classify, nghĩa là phân lớp, phân nhóm.

Vì là thuộc tính, nên idclass có cú pháp là: id=“gia-tri”class=“gia-tri”. Trong đó gia-tri chính là tên mà người lập trình muốn đặt cho một phần tử hoặc một nhóm phần tử.

Giá trị của id và class (quy ước đặt tên)

– Phải bắt đầu bằng kí tự (a-z hoặc A-Z) hoặc dấu gạch dưới ( _ ) (underline)

– Các kí tự tiếp theo có thể là kí tự, số, dấu gạch nối ( - ) (hyphen), dấu gạch dưới, dấu hai chấm (colons), dấu chấm (periods)

– Không chứa kí tự đặc biệt

– Bạn nên định hình một thói quen đặt tên cho riêng mình. Ví dụ: sử dụng chữ thường , nếu tên gồm nhiều từ, thì dùng dấu gạch nối để nối các từ, như: id=“bang-bao-gia”, class=“bai-viet”

Ví dụ, trang web được chia thành ba vùng duy nhất (main, news, links), do vậy có thể dùng phần tử div để chia, và đặt tên cho mỗi vùng bằng thuộc tính id,

<div id="main">

<!-- nội dung của vùng main -->

</div>

 

<div id="news">

<!-- nội dung vùng news -->

</div>

 

<div id="links">

<!-- nội dung vùng links -->

</div>

Với HTML5, có thể sử dụng các phần tử có ngữ nghĩa tốt hơn để thay phần tử trung tính div, ví dụ,

<section id="main">

<!-- nội dung của vùng main -->

</section>

 

<section id="news">

<!-- nội dung vùng news -->

</section>

 

<aside id="links">

<!-- nội dung vùng links -->

</aside>

Ví dụ, để thống nhất việc định dạng cho tên của các thủ đô, sẽ sử dụng thuộc tính class để đặt tên chung cho nhóm thủ đô là city,

<h2 class="city">London</h2>

<p>London là thủ đô của Anh.</p>

<h2 class="city">Paris</h2>

<p>Paris là thủ đô của Pháp.</p>

<h2 class="city">Tokyo</h2>

<p>Tokyo là thủ đô của Nhật bản.</p

Lưu ý: một phần tử có thể vừa chứa id vừa chứa class; một phần tử cũng có thể chứa nhiều class. Ví dụ,

<section id="main" class="content big-font" >

<!-- nội dung của vùng main -->

</section>

<section id="news" class="content">

<!-- nội dung vùng news -->

</section>

<aside id="links">

<!-- nội dung vùng links -->

</aside>

1.1.3       Cải thiện khả năng tiếp cận với ARIA

Người sử dụng web rất đa dạng, thông thường họ hay đọc/xem nội dung, dùng chuột để tương tác với giao diện, chuyển mục, chuyển trang. Tuy nhiên, họ cũng có thể đang sử dụng phần mềm đọc web (screen reader), sử dụng bàn phím, ra lệnh bằng giọng nói thay vì dùng chuột.

Với một tài liệu HTML, con người có thể đọc mã nguồn là hiểu được ý nghĩa của chúng, như là tiêu đề (title), đề mục (heading), danh sách, hình ảnh. Tuy nhiên, với các thiết bị hỗ trợ (assistive divice) thì không dễ, đặc biệt với các phần tử trung tính như div và span. Ngoài ra, với việc phát triển ứng dụng web dùng nhiều JavaScript và AJAX thì việc nhận biết ý nghĩa, trạng thái của các phần tử càng khó khăn hơn.

ARIA (Accessible Rich Internet Applications) là một bộ các thuộc tính, được sử dụng để hỗ trợ quá trình điều hướng, tương tác với trang web.

ARIA định nghĩa các chức năng (role), trạng thái (state) và thuộc tính (property), để lập trình viên có thể thêm vào các phần tử hoặc đoạn mã lập trình, giúp mã nguồn giàu thông tin hơn.

Role

Thuộc tính role cho biết chức năng và mục đích của một phần tử, ví dụ: alert, button, dialog, slider và menubar.

Ví dụ, giả sử bạn dùng ul, li kết hợp với CSS để làm một danh sách các thanh chọn (toolbar). Tuy nhiên, nếu chỉ nhìn vào mã nguồn thì rất khó nhận biết đó là thanh chọn. Để dễ dàng nhận ra, bạn chỉ việc thêm thuộc tính role= “toolbar” vào mã nguồn như sau:

<ul id="tabs" role="toolbar">

          <li>A-G</li>

          <li>H-O</li>

          <li>P-T</li>

          <li>U-Z</li>

     </ul>

Ví dụ, đoạn mã sau cho biết div chứa một thông báo,

<div id="status" role="alert">You are no longer connected to the

          server.</div>

States và properties

ARIA cũng định nghĩa states và properties để sử dụng trong các phần tử tương tác, như các thành phần của form, các nội dung động. States và properties được nhận biết bằng thuộc tính có tiền tố là aria-, ví dụ: aria-disabled, aria-describedby.

1.1.4       Hiển thị các kí tự đặc biệt

Ở đây, kí tự đặc biệt được hiểu là những kí tự thuộc một trong hai loại sau:

- Một là những kí tự không có sẵn trong bảng mã ASCII, hiểu nôm na là không có sẵn trên bàn phím máy tính, muốn có nó thì phải dùng tổ hợp phím, hoặc như trong Microsoft Word thì dùng chức năng chèn kí tự đặc biệt (symbol). Do không nhập được vào mã nguồn, nên trình duyệt sẽ không thể xuất ra màn hình được. Ví dụ, kí hiệu bản quyền (copyright sign): ©.

- Hai là các kí tự trùng với từ khóa (keyword) của HTML, hiểu nôm na là, trong khi người lập trình muốn xuất kí tự đó ra màn hình, nhưng trình duyệt lại hiểu là từ khóa nên nó sẽ biên dịch và thực thi từ khóa. Ví dụ, lập trình viên muốn xuất dấu bé (<), tuy nhiên trình duyệt lại hiểu là phần bắt đầu của thẻ mở.

Như vậy phải có cách nào đó, để ghi được các kí tự này vào mã nguồn (tài liệu HTML), sau đó trình duyệt sẽ hiển thị ra màn hình. Giải pháp HTML đưa ra là, xem các kí tự đặc biệt đó là “thực thể” (entity) chứ không phải kí tự. Vì là thực thể nên phải có dấu hiệu nhận diện, để phân biệt với kí tự thông thường, dấu hiệu nhận diện là bất kì thứ gì nằm giữa dấu “&” và dấu “;” thì được coi là thực thể. Trong HTML, các kí tự đặc biệt này được gọi là “escape character”, có thể hiểu vui vui là “kí tự mà không thể kí (ghi) được” hoặc “tui không phải là kí tự”.

Các kí tự đặc biệt sẽ được viết dưới dạng các thực thể, mỗi kí tự đặc biệt luôn có hai cách viết, viết bằng số gọi là thực thể số (numeric entity); và viết bằng chữ gọi là thực thể chữ (named entity).

Bảng sau là cách viết một số kí tự đặc biệt bằng thực thể,

Kí tự

Mô tả

Thực thể chữ

Thực thể số

 

Kí tự trắng đặc biệt, không bị ngắt (nbsp -nonbreaking space). Ví dụ, để luôn xuất chuỗi “không thể tách rời” thành một khối, nghĩa là cả chuỗi luôn nằm trên cùng một hàng, thì viết như sau: “không&nbsp;thể&nbsp;tách&nbsp;rời”

&nbsp;

&#160;

&

Dấu và (ampersand)

&amp;

&#038;

`

Dấu lược (apostrophe)

&apos;

&#039;

< 

Dấu bé (less-than symbol)

&lt;

&#060;

> 

Dấu lớn (greater-than symbol)

&gt;

&#062;

©

Kí hiệu bản quyền (copyright sign)

&copy;

&#169;

®

Nhãn hiệu đã đăng kí (registered trademark)

&reg;

&#174;

Nhãn hiệu

&trade;

&#8082;

£

Kí hiệu đồng Bảng Anh

&pound;

&#163;

¥

Kí hiệu đồng Yên Nhật

&yen;

&#165;

Kí hiệu đồng Euro

&euro;

&#8364;

– ­­

Dấu gạch ngang (en-dash): dấu gạch ngang có chiều dài bằng chữ “n”. Ví dụ, dùng để gạch đầu hàng, dấu trừ. Đừng nhầm với dấu gạch nối (hyphen) (-)

&ndash;

&#8211;

Dấu gạch đúp (em-dash): dấu gạch đúp có chiều dài bằng chữ “m”. Ví dụ, dùng để chú thích trong một câu.

&mdash;

&#8212;

 Dấu mở nháy đơn (left curly single quote)

&lsquo;

&#8216;

Dấu đóng nháy đơn (right curly single quote)

&rsquo;

&#8217;

Dấu mở nháy kép (left curly double quote)

&ldquo;

&#8220;

Dấu đóng nháy kép (right curly double quote)

&rdquo;

&#8221;

·

Dấu đầu dòng (bullet)

&bull;

&#8226;

Dấu chấm lửng (ngang), hay dấu ba chấm (horizontal ellipsis)

&hellip;

&#8230;

1.1.5       Xem và đọc thêm

– Nhập tên các thẻ vào Google hoặc Youtube để đọc và xem thêm.

– Hoặc đọc từ hai trang là: https://www.w3schools.com/, hoặc https://developer.mozilla.org/en-US/

– Jennifer Niederst Robbins, Learning Web Design, O’REILLY, 2018, p98 – p108

1.1.6       Bài tập và thực hành

Bài tập 1. Viết lại các đoạn mã trong phần lý thuyết.

Bài tập 2. This little post for the Black Goose Bistro News page will give you an opportunity to identify and mark up a variety of inline elements. See if you can find phrases to mark up accurately with the following elements:

b          br         cite       dfn       em       i           q          small    time

Because markup is always somewhat subjective, your resulting markup may not look exactly like my final markup, but there is an opportunity to use all of the preceding elements in the article. For extra credit, there is a phrase that could have two elements applied to it. (Hint: look for a term in another language.) Remember to nest them properly by closing the inner element before you close the outer one. Also, be sure that all text-level elements are contained within block elements.

[The post]

<article>

<header>

<p>posted by BGB, November 15, 2016</p>

</header>

<h2>Low and Slow</h2>

<p>This week I am extremely excited about a new cooking technique called sous vide. In sous vide cooking, you submerge the food (usually vacuum-sealed in plastic) into a water bath that is precisely set to the target temperature you want the food to be cooked to. In his book, Cooking for Geeks, Jeff Potter describes it as ultra-low-temperature poaching.</p>

<p>Next month, we will be serving Sous Vide Salmon with Dill Hollandaise. To reserve a seat at the chef table, contact us before November 30.</p>

<p>blackgoose@example.com

555-336-1800</p>

<p>Warning: Sous vide cooked salmon is not pasteurized. Avoid it if you are pregnant or have

immunity issues.</p>

</article>

Bài tập 3. The Black Goose Bistro News page.

Now that you’ve been introduced to all of the text elements, you can put them to work by marking up the News page for the Black Goose Bistro site.

Below is the started text, follow the instructions listed after it to finish the web page.  

[Started text]

The Black Goose Bistro News

Home

Menu

News

Contact

Summer Menu Items

posted by BGB, June 18, 2017

Our chef has been busy putting together the perfect menu for the summer months. Stop by to try these appetizers and main courses while the days are still long.

Appetizers

Black bean purses

Spicy black bean and a blend of Mexican cheeses wrapped in sheets of phyl-lo and baked until golden. $3.95

Southwestern napoleons with lump crab -- new item!

Layers of light lump crab meat, bean and corn salsa, and our handmade flour tortillas. $7.95

Main courses

Shrimp sate kebabs with peanut sauce

Skewers of shrimp marinated in lemongrass, garlic, and fish sauce then grilled to perfection. Served with spicy peanut sauce and jasmine rice. $12.95

Jerk rotisserie chicken with fried plantains -- new item!

Tender chicken slow-roasted on the rotisserie, flavored with spicy and fragrant jerk sauce and served with fried plantains and fresh mango. $12.95

Low and Slow

posted by BGB, November 15, 2016

<p>This week I am <em>extremely</em> excited about a new cooking technique called <dfn><i>sous vide</i></dfn>. In <i>sous vide</i> cooking, you submerge the food (usually vacuum-sealed in plastic) into a water bath that is precisely set to the target temperature you want the food to be cooked to. In his book, <cite>Cooking for Geeks</cite>, Jeff Potter describes it as <q>ultra-low-temperature poaching.</q></p>

<p>Next month, we will be serving <b><i>Sous Vide</i> Salmon with Dill Hollandaise</b>. To reserve a seat at the chef table, contact us before <time datetime="20161130">November 30</time>.</p>

Location: Baker's Corner, Seekonk, MA

Hours: Tuesday to Saturday, 11am to 11pm

All content copyright 2017, Black Goose Bistro and Jennifer Robbins

1. Start by adding the DOCTYPE declaration to tell browsers this is an HTML5 document.

2. Add all the document structure elements first (html, head, meta, title, and body). Give the document the title “The Black Goose Bistro News”

3. The first thing we’ll do is identify the top-level heading and the list of links as the header for the document by wrapping them in a header element (don’t forget the closing tag). Within the header, the headline should be an h1 and the list of links should be an unordered list (ul). Don’t worry about making the list items links; we’ll get to linking in the next chapter. Give the list more meaning by identifying it as the primary navigation for the site (nav).

4. The News page has two posts titled “Summer Menu Items” and “Low and Slow.” Mark up each one as an article.

5. Now we’ll get the first article into shape. Let’s create a header for this article that contains the heading (h2 this time because we’ve moved down in the document hierarchy) and the publication information (p). Identify the publication date for the article with the time element.

6. The content after the header is a simple paragraph. However, the menu has some interesting things going on. It is divided into two conceptual sections (Appetizers and Main Courses), so mark those up as section elements. Be careful that the final closing section tag (</section>) appears before the closing article tag (</article>) so the elements are nested correctly and don’t overlap. Finally, let’s identify the sections with id attributes. Name the first one “appetizers” and the second “maincourses.”

7. With our sections in place, now we can mark up the content. We’re down to h3 for the headings in each section. Choose the most appropriate list elements to describe the menu item names and their descriptions. Mark up the lists and each item within the lists.

8. Now we can add a few fine details. Classify each price as “price” using span elements.

9. Two of the dishes are new items. Change the double hyphens to an em dash character and mark up “new item!” as “strongly important.” Classify the title of each new dish as “newitem” (use the existing dt element; there is no need to add a span this time). This allows us to target menu titles with the “newitem” class and style them differently than other menu items.

10. That takes care of the first article. The second article is already mostly marked up from the previous exercise, but you should mark up the header with the appropriate heading and publication date information.

11. So far, so good, right? Now make the remaining content that applies to the whole page a footer. Mark each line of content within the footer as a paragraph.

12. Let’s give the location and hours information some context by putting them in a div named “about.” Make the labels “Location” and “Hours” appear on a line by themselves by adding line breaks after them. Mark up the hours with the time element (you don’t need the date or time zone portions).

13. Finally, copyright information is typically “small print” on a document, so mark it up accordingly. As the final touch, add a copyright symbol after the word “copyright” using the keyboard or the &copy; character entity.

Save the as bistro_news.html, and check your page in a modern browser. You can also upload it to validator.nu and make sure it is valid (it’s a great way to spot mistakes). How did you do?

[Gợi ý làm bài tập]

Bài tập 2.

[post.html]

<article>

<header>

<p>posted by BGB, <time datetime="2016-11-15">November 15, 2016</time></p>

</header>

<h2>Low and Slow</h2>

<p>This week I am <em>extremely</em> excited about a new cooking technique called <dfn><i>sous vide</i></dfn>. In <i>sous vide</i> cooking, you submerge the food (usually vacuum-sealed in plastic) into a water bath that is precisely set to the target temperature you want the food to be cooked to. In his book, <cite>Cooking for Geeks</cite>, Jeff Potter describes it as <q>ultra-low-temperature poaching.</q></p>

<p>Next month, we will be serving <b><i>Sous Vide</i> Salmon with Dill Hollandaise</b>. To reserve a seat at the chef table, contact us before <time datetime="2016-11-30">November 30</time>.</p>

 

<p>blackgoose@example.com<br>

555-336-1800</p>

 

<p><small>Warning: <i>Sous vide</i> cooked salmon is not pasteurized. Avoid it if you are pregnant or have immunity issues.</small></p>

</article>

Bài tập 3.

[bistro_news.html]

<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <title>The Black Goose Bistro News</title>

</head>

<body>

    <header>

        <h1>The Black Goose Bistro News</h1>

        <nav>

            <ul>

                <li>Home</li>

                <li>Menu</li>

                <li>News</li>

                <li>Contact</li>

            </ul>

        </nav>

    </header>

    <article>

        <header>

            <h2>Summer Menu Items</h2>

            <p><time datetime="2017-6-18">posted by BGB, June 18, 2017</time></p>

        </header>

        <p>Our chef has been busy putting together the perfect menu for the summer

            months. Stop by to try these appetizers and main courses while the

            days are still long.</p>

        <section id="appetizers">

            <h3>Appetizers</h3>

            <dl>

                <dt>Black bean purses</dt>

                <dd>Spicy black bean and a blend of Mexican cheeses wrapped in

                    sheets of phyl-lo and baked until golden. $3.95</dd>

                <dt class="newitem">Southwestern napoleons with lump crab &mdash; <strong>new item!</strong></dt>

                <dd>Layers of light lump crab meat, bean and corn salsa,

                    and our handmade flour tortillas. $7.95</dd>

            </dl>

        </section>

        <section id="maincourses">

            <h3>Main courses</h3>

            <dl>

                <dt>Shrimp sate kebabs with peanut sauce</dt>

                <dd>Skewers of shrimp marinated in lemongrass, garlic,

                    and fish sauce then grilled to perfection. Served

                    with spicy peanut sauce and jasmine rice. <span class="price">$12.95</span></dd>

                <dt class="newitem">Jerk rotisserie chicken with fried

                    plantains &mdash;<strong>new item!</strong></dt>

                <dd>Tender chicken slow-roasted on the rotisserie, flavored

                    with spicy and fragrant jerk sauce and served with fried

                    plantains and fresh mango. <span class="price">$12.95</span></dd>

            </dl>

        </section>

    </article>

    <article>

        <heaer>

            <h2>Low and Slow</h2>

            <p>posted by BGB, <time datetime="2016-11-15">November 15, 2016</time></p>

        </heaer>

        <p>This week I am <em>extremely</em> excited about a new cooking technique

            called <dfn><i>sous vide</i></dfn>. In <i>sous vide</i> cooking, you submerge

            the food (usually vacuum-sealed in plastic) into a water bath that is precisely

            set to the target temperature you want the food to be cooked to. In his

            book, <cite>Cooking for Geeks</cite>, Jeff Potter describes it

            as <q>ultra-low-temperature poaching.</q></p>

        <p>Next month, we will be serving <b><i>Sous Vide</i> Salmon with Dill Hollandaise</b>.

            To reserve a seat at the chef table, contact us

            before <time datetime="20161130">November 30</time>.</p>

    </article>

    <footer>

        <div id="about">

            <p>Location:<br> Baker's Corner, Seekonk, MA</p>

            <p>Hours:<br> Tuesday to Saturday, <time datetime="11:00">11am</time>

                to <time datetime="23:00">11pm</time></p>

        </div>

        <p><small>All content copyright &copy; 2017, Black Goose Bistro and Jennifer Robbins</small></p>

    </footer>

</body>

</html>

[Kết quả Bài tập 3]


1.1.7       Câu hỏi ôn tập

Câu hỏi 1. Phần tử HTML nào sau đây không phải là phần tử kiểu inline?

A. small

B. p

C. strong

D. a

Câu hỏi 2. Phát biểu nào sau đây không đúng, khi nói về phần tử HTML trung tính (generic element)

A. Phần tử trung tính có ngữ nghĩa rõ ràng, cụ thể

B. div và span là hai phần tử trung tính

C. div là phần tử trung tính kiểu khối

D. Khi không thể tìm được phần tử có ngữ nghĩa thì mới lựa chọn phần tử trung tính

Câu hỏi 3. Trong HTML, ARIA dùng để làm gì?

A. Là một loại phông chữ

B. Là một bộ các thuộc tính, được sử dụng để hỗ trợ quá trình điều hướng, tương tác với trang web.

C. Là một phần tử, dùng để nhúng âm thanh vào trang web

D. Là một phần tử, dùng để nhúng video vào trang web

Câu hỏi 4. Để hiển thị kí hiệu bản quyền (copyright sign) ra ngoài giao diện, mã HTML sẽ là:

A. &copyright;

B. copyright;

C. &copy;

D. &copy

Câu hỏi 5. Để hiển thị thêm các khoảng trắng (nonbreaking space) ra ngoài giao diện, mã HTML sẽ là:

A. &space;

B. &space

C. &nbsp

D. &nbsp;

Đáp án: 1(B), 2(A), 3(B), 4(C), 5(D)

-----

Xem video bài giảng

Cập nhật: 10/5/2024
-----
Tải tài liệu đầy đủ: Tự học HTML căn bản
-----