banner image

Sự khác nhau giữa những điều tưởng giống nhau

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

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

- 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.
hide element

3. Normalize với Reset CSS

Normalize vs 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.

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. vscode

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.
thẻ section
  • 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
thẻ heading Để 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, screenX, screenY, clientX và clientY

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

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 và width

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)
curent target


<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 Sự khác nhau giữa những điều tưởng giống nhau Reviewed by kentrung on May 31, 2021 Rating: 5

No comments:

Powered by Blogger.