Bài viết tổng hợp những điều tưởng giống nhau nhưng thực ra khác nhau VL trong HTML - CSS - JAVASCRIPT. Bài viết được tổng hợp chủ yếu tại đây của tác giả Hữu Khuyên
Nếu anh em dùng kèm một số thư viện CSS như Bootstrap, Material... thì họ đã có sẵn phần reset CSS rồi. Còn nếu một module riêng của bản thân thì chúng ta phải tự định nghĩa một đoạn reset css / normalize css của riêng mình. Vậy khác nhau giữa 2 cái này là gì?
Các bài viết tham khảo: https://viblo.asia/s/su-khac-nhau-giua-nhung-dieu-tuong-giong-nhau-L6lAy1oglek
1. style="width: ..." và width="..."
Chắc hẳn những bạn làm Frontend lâu năm đôi khi cũng hay nhầm lẫn giữa hai thuộc tính này.
<!-- Work -->
<img width="200px" />
<!-- Does NOT work -->
<div width="200px">
Trước tiên đây là cách để khai báo một attribute cho một tag HTML, thường gọi là CSS inline style.
<div style="..."></div>
- HTML Attribute Reference
- Đối với width, height là thuộc tính có sẵn của HTML, không phải của CSS.
- Chỉ dùng được cho các tag như canvas, img, table, input, iframe ...
- Document: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
- Style Attribute
- Cách viết css trong thẻ style sẽ có độ ưu tiên hơn.
- Sử dụng được nhiều thuộc tính CSS
2. display: none, opacity: 0 và visibility: hidden
Trong CSS, có 3 thuộc tính để ẩn element là
display: none;
opacity: 0;
visibility: hidden;
display: none
- Là cách sử dụng phổ biến nhất, cách này sẽ xoá luôn kích thước của element.
- Không sử dụng cho mục đích làm hiệu ứng như fade, slideToggle...
- Vì bị mất kích thước thực tế bằng 0 nên các properties liên quan đến size sẽ không sử dụng được: clientHeight, clientWidth, height, offsetHeight, offsetWidth, scrollHeight, scrollWidth kể cả là getBoundingClientRect()
opacity: 0
- Làm element bị trong suốt giống như kiểu tàng hình ý, tuy nhiên vẫn giữ lại kích thước cho vị trí hiện tại.
- Thường dùng kết hợp với CSS3 cho các trường hợp animation fade...
visibility: hidden
- Là thuộc tính kết hợp giữa opacity: 0 và pointer-events: none, cách này thường dùng để vô hình một element tuy nhiên không muốn tác động thông qua việc hover, thao tác tab...
Thủ thuật
Với Chrome hoặc Firefox khi bật F12, trong lúc debug CSS bạn cũng có thể ẩn bất kỳ element nào bằng cách selector đến element đó và ấn phím h hoặc chuột phải chọn hide element.3. Normalize với Reset CSS
Nhìn chung, normalize và reset đều là phần định nghĩa chung để thống nhất các trình duyệt có style tương tự nhau. Ví dụ để thống nhất border của input, để loại bỏ margin mặc định của body...Nếu anh em dùng kèm một số thư viện CSS như Bootstrap, Material... thì họ đã có sẵn phần reset CSS rồi. Còn nếu một module riêng của bản thân thì chúng ta phải tự định nghĩa một đoạn reset css / normalize css của riêng mình. Vậy khác nhau giữa 2 cái này là gì?
Reset CSS
- Như cái tên của nó, nó sẽ reset lại các style mặc định để thống nhất lại những điểm chung của các trình duyệt (Chrome / Firefox / Safari / IE...).
- Áp dụng cho các tag h1 -> h6, p, strong, em
- Loại bỏ spacing mặc định của trình duyệt
- Loại bỏ border space của table và bỏ style list mặc định của ul, li
Normalize
- Mục đích bổ sung, định nghĩa style common để phù hợp với project của bạn.
- Chia thành modules, phục vụ cho nhiều components khác nhau mà không bị ảnh hưởng như reset
Thư viện
Có một vài thư viện định nghĩa sẵn việc này bạn có thể tham khảo.- Reset CSS: https://meyerweb.com/eric/tools/css/reset/
- Reseter.css: https://krishdevdb.github.io/reseter.css/
- Normalize.css: https://necolas.github.io/normalize.css/
4. alt và title
Đều là 2 thuộc tính sử dụng phổ biến đối với <img />. Tuy nhiên, mỗi thuộc tính lại có một chức năng riêng.
<img
src="./images/ahihi.jpg"
alt="Sự khác nhau giữa những điều tưởng giống nhau - Phần 2"
title="Sự khác nhau giữa những điều tưởng giống nhau - Phần 2"
/>
alt
- Thuộc tính alt là văn bản thay thế dùng làm nội dung của element khi element không được hiển thị bình thường. Nó là thuộc tính được sử dụng phổ biến ở thẻ <img />.
- Khi không thể tải hình ảnh, trình duyệt sẽ hiển thị văn bản thay thế ở vị trí của nó để người dùng có thể biết lý do tại sao hình ảnh được đưa vào.
- alt là thuộc tính quan trọng để "tham dự" trong kho tìm kiếm của Google, được khuyến khích sử dụng nếu muốn SEO.
title
- Thuộc tính title là văn bản chú thích được nhìn thấy khi được hover.
- Ngoài việc sử dụng trên img, nó còn được sử dụng ở nhiều tag khác, thường dùng cho trường hợp thay thế như tooltip, truncate text...
Tips
Thông thường, khi làm việc với img, anh em thường quên việc định nghĩa alt điều này rất không nên vì nó sẽ ảnh hưởng đến chất lượng SEO của bạn. Vì vậy, mình sẽ có 1 thủ thuật bằng CSS để nhận diện những hình ảnh chưa có alt.
// Những thanh niên img nào chưa có "alt" sẽ được sáng nhất đêm nay
img:not([alt]), img[alt=""] {
outline: 8px solid red;
}
Còn đối với anh em nào dùng VS Code có thể sử dụng extension webhint để giúp cảnh báo điều đó dễ dàng.
5. <button> và <input type="button" />
button
- Có thể sử dụng pseudo-elements như :before và :after để style
- Attribute mặc định của <button> là type="submit", nếu không được định nghĩa, khi submit vẫn hoạt động được trong thẻ <form>
input type="button"
- Không thể sử dụng pseudo-elements như :before và :after vì <input /> là thẻ single tag
- Để có thể submit được form, phải đổi lại <input type="submit" />
Tips
- Nên sử dụng tag <button> vì có thể khai thác được tối đa style.
- Nên định nghĩa rõ ràng attribute cho từng chức năng của button, ví dụ
<button type="submit"> // submit form
<button type="reset"> // reset lại giá trị ban đầu của form
<button type="button"> // không làm gì cả, ấn cho vui
6. <div> và <section>
Phiên bản HTML5 đã cho ra thuật ngữ Semantic Elements - là những tag mới được ra mắt. Trong đó thẻ <section> được khuyến khích sử dụng thay thế cho <div>. Vậy nó khác nhau những gì?div
- div là thẻ đã quá quen thuộc, tuy nhiên nó không có ý nghĩa đặc biệt. Thường được sử dụng như một khối của phần tử con (thông thường nếu muốn tag đó mặc định là display=block).
- Ngoài sự khác biệt về semantic, div có constructor interface riêng là HTMLDivElement.
section
- Sinh ra để nhóm các element con liên quan, thường dùng cho 1 đoạn content.
- Ví dụ bên trên, <section> sẽ là thẻ wrapper bao phần title <h3> và những đoạn text <p>, <img /> và cũng có thể bao những thẻ <div> khác.
- Ngoài section ra thì các thẻ semantic khác như article, footer, header, main, navbar lại có cùng constructor interface là HTMLElement.
Tips
- Có một điều thú vị là nếu phần tử heading được lồng ở nhiều cấp section, khi đó font-size của mỗi cấp element heading sẽ giảm xuống. Còn đối với div thì không bị ảnh hưởng.
section
h1 Section title
section
h1 Title sub section
div
h1 Div title
div
h1 Title sub div
Để tận dụng điều này, anh em có thể style cấp độ font-size của các heading thông qua đoạn CSS sau
/* First level */
:-webkit-any(article,aside,nav,section) h1 {
font-size: 1.5em;
}
/* Second level */
:-webkit-any(article,aside,nav,section)
:-webkit-any(article,aside,nav,section) h1 {
font-size: 1.2em;
}
/* Third level */
:-webkit-any(article,aside,nav,section)
:-webkit-any(article,aside,nav,section)
:-webkit-any(article,aside,nav,section) h1 {
font-size: 1.00em;
}
/* Fourth level */
:-webkit-any(article,aside,nav,section)
:-webkit-any(article,aside,nav,section)
:-webkit-any(article,aside,nav,section)
:-webkit-any(article,aside,nav,section) h1 {
font-size: .8em;
}
- Nên sử dụng section cho những đoạn content lớn thay vì chỉ dùng div truyền thống.
- Mặc định, các element không được xác định sẽ có kiểu mặc định là display: inline, vì vậy cần phải cần reset những tag mới của HTML5
article, aside, footer, header, nav, section {
display: block;
}
- HTML5 semantic chỉ hỗ trợ cho phiên bản IE 9 trở lên, nếu bạn vẫn muốn được support thì có thể convert bằng cách
<!--[if lt IE 9]>
<script>
document.createElement("article");
document.createElement("aside");
document.createElement("footer");
document.createElement("header");
document.createElement("nav");
document.createElement("section");
</script>
<![endif]-->
7. pageX, pageY, screenX, screenY, clientX và clientY
Để dễ hình dung, bạn có thể xem hình minh hoạ sau.pageX / pageY
- Dựa vào cái tên, chúng ta cũng đã thấy phản ánh lên được mục đích của nó.
- Toạ độ page bắt đầu từ vị trí trên cùng bên trái, toạ độ tính từ gốc <html>, hiểu nôm na là bắt đầu từ phần top: 0 / left: 0 của trang web, nó sẽ bao gồm các phần bị ẩn khi scroll. Toạ độ này cũng có thể ở bất kỳ đâu trong cửa sổ trình duyệt và có thể thay đổi vị trí nếu nó được embed vào trang khác khi người dùng scroll.
clientX / clientY
- clientX / Y cung cấp tọa độ tương ứng với các viewport CSS.
- Tương đối với mép (góc) trên bên trái của cửa sổ trình duyệt. Điểm này có thể di chuyển khi người dùng di chuyển / resize trình duyệt xung quanh màn hình. Điểm này không di chuyển kể cả khi được scroll từ bên trong trình duyệt.
screenX / screenY
- Tương tự là dùng để lấy giá trị toạ độ, điểm bắt đầu cũng xuất phát từ mép trên cùng bên trái. Nhưng ở đây nó sẽ chỉ thay đổi khi tăng giảm độ phân giải màn hình.
- screenX / Y cho tọa độ tương ứng với các screenpixel trong thiết bị.
8. offsetHeight, clientHeight, scrollHeight
scrollHeight
- Là phép đo chiều cao thực tế của một element bao gồm cả content không hiển thị do bị giới hạn bởi vùng scroll.
- scrollHeight = ENTIRE content + padding
clientHeight
- Là phép đo theo chiều cao CSS của element, bao gồm border, padding và thanh scroll ngang (nếu có).
- clientHeight = VISIBLE content + padding
offsetHeight
- Tương tự như clientHeight, tuy nhiên không tính thêm size của border.
- offsetHeight = VISIBLE content + padding + border + scrollbar
- Để dễ hình dung, anh em có thể xem qua demo này: https://codepen.io/nguyenhuukhuyenudn/full/qBRgeQB
9. naturalWidth và width
Cả 2 phương thức trên đều trả về giá trị px của 1 element, thường dùng cho trường hợp get size của image. Tuy nhiên mỗi cái lại có một chức năng và mục đích khác nhau.naturalWidth
- Trả về chiều rộng thực tế của một element. Là giá trị không bao giờ thay đổi. Ví dụ: 1 tấm hình rộng 100px luôn có width tự nhiên là 100px ngay cả khi image được thay đổi kích thước bằng CSS hoặc JavaScript.
width
- Là chiều rộng đo được khi đã được can thiệp bởi CSS hoặc Javascript.
10. preventDefault() và return false
Đều có tác dụng ngăn chặn sự kiện mặc định xảy ra.preventDefault()
Ví dụ khi nhấp vào link, ta có thể chặn việc thực hiện điều hướng bằng cách
hyperlink.addEventListener('click', function(e) {
// Don't redirect user to the link
e.preventDefault();
});
Tương tự đối việc submit form
submitButton.addEventListener('click', function(e) {
// Don't submit the form when clicking a submit
e.preventDefault();
})
return false
- Không hoạt động trên thông qua addEventListener
- Chỉ hoạt động khi handle event được khai báo là attribute của element
hyperlink.addEventListener('click', function(e) {
// Does NOT work
return false;
});
// Work
hyperlink.onclick = function(e) {
return false;
};
Nếu bạn đang sử dụng jQuery để quản lý các event, thì bạn có thể sử dụng return false trong trình xử lý sự kiện:
$('button').click(function (event) { // cần có tham số truyền vào
// code ...
event.preventDefault()
});
$('button').click(function () { // không cần tham số truyền vào
// code ...
return false;
});
- Ngăn cản event ảnh hưởng tới parrent element giống như event.stopPropagation() (Best practice)
<p onclick="parentEventHandler()">
<a href="https://viblo.asia">Viblo</a>
</p>
<script type="text/javascript">
// hàm callback xử lý sự kiện click vào phần tử "p"
function parentEventHandler() {
alert("bạn đã nhấp chuột vào phần tử p");
};
// đoạn mã jQuery đăng ký hàm callback để xử lý sự kiện click vào phần tử "a"
$("a").click(function (event) {
alert("bạn đã nhấp vào link");
return false;
});
</script>
Khi người dùng nhấp vào link liên kết một hộp thoại cảnh báo được hiện ra với nội dung bạn đã nhấp vào link. Sau đó sẽ không có bất cứ hành động nào khác diễn ra do return false ngăn cản browser điều hướng tới trang đích của liên kết đồng thời ngăn cản sự kiện nhấp chuột ảnh hưởng tới phần tử cha là p.
11. currentTarget và target
target
- target cho biết nơi bắt đầu sự kiện.
- Là phần tử mà người dùng đã nhấp vào, trong trường hợp sự kiện click. Nó có thể là phần tử gốc hoặc bất kỳ phần tử con nào của nó tùy thuộc vào nơi được người dùng click vào chính xác.
currentTarget
- currentTarget cho chúng ta biết phần tử nào mà sự kiện đã được đính kèm hoặc phần tử có eventListener đã kích hoạt sự kiện, nói chung là để lắng nghe sự kiện.
- Giả sử bạn xây dựng modal, modal sẽ được 1 lớp overlay bao bên ngoài, khi click ra ngoài sẽ close modal (click outside)
<div id="overlay">
<div id="modal">...</div>
</div>
<script>
let overlay = document.getElementById('overlay');
let modal = document.getElementById('modal');
</script>
Đầu tiên, mình sẽ detect việc click vào #overlay
overlay.addEventListener('click', function() {
// To do close modal
console.log('Close the modal');
});
Tuy nhiên, khi người dùng click lên #modal thì #overlay cũng được click. Vì vậy, cần sử dụng stopPropagation() để ngăn chặn event ảnh hưởng tới phần tử cha.
modal.addEventListener('click', function(e) {
e.stopPropagation();
});
Cách thứ 2, để đảm bảo rằng người dùng nhấp vào #overlay chứ không phải #modal, chúng ta có thể chỉ cần kiểm tra xem cả thuộc tính currentTarget và target có tham chiếu đến cùng một phần tử hay không:
overlay.addEventListener('click', function(e) {
if (e.currentTarget === e.target) {
// To do close modal
console.log('Close the modal');
}
});
Cách làm thứ hai đơn giản hơn nhiều so với cách đầu tiên và nó không yêu cầu handle sự kiện nhấp chuột của modal.
12. addEventListener() function và on property
addEventListener
Các phiên bản cũ < 9 của của IE - phần mềm để down chrome thực hiện javascript khác với khá nhiều trình duyệt khác. Với các phiên bản nhỏ hơn 9, ta sử dụng phương thức attachEvent
element.attachEvent('onclick', function() {
/* do stuff here*/
});
Cho đến khi IE 10 ra đời, addEventListener đã ra đời và thay thế cho attachEvent
element.addEventListener('click', function() {
/* do stuff here*/
}, false);
- Handle được nhiều sự kiện với addEventListener
- Cho phép handle event không giới hạn và remove chúng với element.removeEventListener().
- Cho phép tách file (HTML) và logic (JavaScript) giúp viết rõ ràng và dễ quản lý hơn.
- Hoạt động hầu hết tất cả các trình duyệt. Nếu vẫn phải hỗ trợ IE <= 8, thì có thể sử dụng polyfill từ MDN.
const handler = () => {
console.log('the element is clicked');
};
element.addEventListener('click', handler);
on property (onevent HTML attribute)
element.onclick = handler;
<div onclick="handler()" />
<div onclick="javascript: handler()" />
- Thường gặp vấn đề về lỗ hổng bảo mật XSS.
- Khó quản lý vì viết trong HTML thay vì viết ở file JS xử lý logic riêng
- addEventListener có thể thêm nhiều event, trong khi với onclick điều này không thể thực hiện được
Tổng kết
Bài chia sẻ trên là một số điểm khác biệt mà quá trình làm mình đã nhận ra. Hi vọng sau bài này sẽ giúp các bạn có thêm nhiều thủ thuật mới để giải quyết được nhiều task mà tối ưu nhất. Cảm ơn bạn đã đồng hành cùng những chuyến du lịch của mình. Hãy đón chờ những bài sau để cùng mình khám phá những địa danh mới nhé. 😛Các bài viết tham khảo: https://viblo.asia/s/su-khac-nhau-giua-nhung-dieu-tuong-giong-nhau-L6lAy1oglek
Sự khác nhau giữa những điều tưởng giống nhau
Reviewed by kentrung
on
May 31, 2021
Rating:
No comments: