Hướng dẫn css header fixed top - tiêu đề css cố định trên cùng

Mục tiêu

Tạo bố cục các fixed header và fixed footer

Luyện tập sử dụng thuộc tính position để tạo fixed menu.

Một thiết kế menu điều hướng độc đáo sẽ góp phần thu hút người dùng sử dụng và ở lại trên thiết kế web của bạn. Fixed menu là một xu hướng được nhiều trang web lựa chọn vì gọn nhẹ, lại dễ dàng sử dụng.

Fixed menu, hay còn gọi là floating menu, là menu được gắn cố định ở một vị trí trên trang kể cả khi bạn cuộn trang lên xuống.

Kết quả của phần thực hành là một menu như sau:

Hướng dẫn

Bước 1. Tạo html cơ bản Tạo html cơ bản

Bước 2. Tạo cấu trúc menu : thêm đoạn code sau vào thẻ

Bước 3. Bổ sung mã CSS: Bổ sung mã CSS:

Trong đó, một số thuộc tính quan trọng của class navbar là:

  • Thuộc tính position có giá trị là fixed. Đây là cách để giữ cho menu cố định tại một vị trí
  • Thuộc tính top có giá trị là 0. Nó xác định vị trí trên cùng của trình duyệt.
  • Thuộc tính width có giá trị là 100%. Nó xác định độ rộng của menu sẽ bằng độ rộng của trình duyệt.

Trên đây CodeGym đã cùng với bạn luyện tập sử dụng thuộc tính position để tạo fixed menu. Hãy chụp ảnh màn hình và nộp bài thực hành của bạn trên CodeGymX để cùng nhau luyện tập nhé!

Như chúng ta đã biết, khi click vào một thẻ a có chứa hash, như dưới đây:

<a href="#section-2">Section 2a>

Trình duyệt sẽ scroll tới vị trí của element có ID là "section-2" và nó sẽ scroll đến vị trí nhỏ nhất có thể để element đó hiển thị đầy đủ nhất trên màn hình.

Một vài vấn đề đau đầu thường gặp khi sử dụng thẻ a với hash nhằm mục đích tạo hành động scroll:

  • Có thể gây nhầm lẫn (đặc biệt là khi link đó nhảy đến một khu vực có chứa các tiêu đề khác).
  • Khi mà
    <header>
        ...
            <a href="#goto">Jumpa>
        ...
    header>
    
    <section class="section">
      <span id="section-1"> span>
      <h2>Section 1h2>
        ...
    section>
    
    0 có
    <header>
        ...
            <a href="#goto">Jumpa>
        ...
    header>
    
    <section class="section">
      <span id="section-1"> span>
      <h2>Section 1h2>
        ...
    section>
    
    1
  • ...

Việc

<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
0 có
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
1 là mối đe dọa lớn nhất, chúng ta sẽ xem xét một vài cách xử lý vấn đề đó trong bài viết này

Dirty HTML Method

Thay vì tập trung vào việc xử lý vấn đề trước tiên như chúng ta thường làm, thì hãy xem cách xử lý vấn đề đó thích hợp cho nhiều trình duyệt trước đã.

Chúng ta sẽ không đặt

<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
4 cho thẻ
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
5 (hoặc các thẻ heading) như bình thường, thay vào đó chúng ta sẽ đặt nó vào một thẻ
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
6 trống đặt bên trong
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
5 hoặc các thẻ heading. Nó sẽ không xuất hiện bên trong các thẻ đó, tuy nhiên sử dụng
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
6 cho mục đích này không phải là ý kiến hay.

<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>

Tiếp theo chúng ta sẽ styles cho thẻ

<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
6 đó với giá trị của
.section span{
    margin-top: -80px;        /* Size of fixed header */
    padding-bottom: 80px;
    display: block;
}
0là giá trị âm của chiều cao
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
0. Sau đó, chúng ta sẽ đẩy
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
0 lại vị trí cũ với giá trị của
.section span{
    margin-top: -80px;        /* Size of fixed header */
    padding-bottom: 80px;
    display: block;
}
3 bằng chiều cao của
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
0 đó.styles cho thẻ
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
6 đó với giá trị của
.section span{
    margin-top: -80px;        /* Size of fixed header */
    padding-bottom: 80px;
    display: block;
}
0là giá trị âm của chiều cao
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
0. Sau đó, chúng ta sẽ đẩy
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
0 lại vị trí cũ với giá trị của
.section span{
    margin-top: -80px;        /* Size of fixed header */
    padding-bottom: 80px;
    display: block;
}
3 bằng chiều cao của
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
0 đó.

.section span{
    margin-top: -80px;        /* Size of fixed header */
    padding-bottom: 80px;
    display: block;
}

Cuối cùng, chúng ta sẽ có được một page hoạt động đúng như ý chúng ta muốn.

Clean HTML Method

Sử dụng một thẻ

<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
6 ở vị trí đó khiến code khó hiểu, cơ bản thề
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
6 không nên đặt ở đó, ngoài ra chúng ta dẫn link đến một thẻ
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
6 trống - điều này thật vô nghĩa. Code HTML nên giống như dưới đây:

<section id="section-1" class="section">
  <h2>Section 1h2>
    ...
section>

Chúng ta sẽ xử lý bước tiếp theo bằng CSS bằng cách sử dụng pseudo element thay cho nhiệm vụ của thẻ

<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
6 ở cách trên. Chúng ta sẽ set giá trị cho
.section span{
    margin-top: -80px;        /* Size of fixed header */
    padding-bottom: 80px;
    display: block;
}
9 với giá trị bằng chiều cao của
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
0, sau đó set giá trị âm cho
.section span{
    margin-top: -80px;        /* Size of fixed header */
    padding-bottom: 80px;
    display: block;
}
0 để đẩy phần nội dung về lại vị trí cũ.

.section{
  &::before{
    display: block; 
    content: ""; 
    margin-top: -80px; 
    height: 80px; 
    visibility: hidden; 
    pointer-events: none;
  }
  ...
}

Và chúng ta đã có một kết quả ưng ý với một cách làm tốt hơn rất nhiều

Scroll-padding-top

Như chúng ta thấy, hai cách trên đã giúp chúng ta xử lý đc vấn đề nêu ra, nhưng nó lại không giải quyết được trong trường hợp

<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
5 của chúng ta có
.section span{
    margin-top: -80px;        /* Size of fixed header */
    padding-bottom: 80px;
    display: block;
}
3. Lúc này thì header lại tiếp tục che đi nội dung của
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
5 (cụ thể ở đây là title của
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
5). Để xử lý trường hợp này, chúng ta sẽ sử dụng
<section id="section-1" class="section">
  <h2>Section 1h2>
    ...
section>
6 mà cụ thể ở đây là
<section id="section-1" class="section">
  <h2>Section 1h2>
    ...
section>
7. Tuy nhiên trước đó chúng ta sẽ tìm hiểu xem
<section id="section-1" class="section">
  <h2>Section 1h2>
    ...
section>
6 là gì?

<section id="section-1" class="section">
  <h2>Section 1h2>
    ...
section>
6 là một phần của CSS Scroll Snap Module,
<section id="section-1" class="section">
  <h2>Section 1h2>
    ...
section>
6 được sử dụng để điều chỉnh lại vị trí của element đối với viewport khi scroll đến element đó. Nó rất hiệu quả khi xử lý fixed header che mất nội dung. (chi tiết mọi người có thể tham khảo tại đây)CSS Scroll Snap Module,
<section id="section-1" class="section">
  <h2>Section 1h2>
    ...
section>
6 được sử dụng để điều chỉnh lại vị trí của element đối với viewport khi scroll đến element đó. Nó rất hiệu quả khi xử lý fixed header che mất nội dung. (chi tiết mọi người có thể tham khảo tại đây)

html, body{
  scroll-padding-top: 80px; /* Size of fixed header */
}

Tuy nhiên

<section id="section-1" class="section">
  <h2>Section 1h2>
    ...
section>
6 lại có một số hạn chế về browser hỗ trợ, cụ thể như dưới đây (tham khảo tại Can i use)

JS/jQuery Method

Chúng ta đều biết Javascript (hay jQuery) rất mạnh trong các tùy biến trên web page, tạo ra những hiệu ứng cũng như các trải nghiệm người dùng vô cùng tuyệt vời. Điều này không cần phải bàn luận thêm gì nữa, hãy cùng xem cách giải quyết thông qua JS hoặc jQuery.

Cụ thể, chúng ta sẽ lấy height của

<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
0 và
.section{
  &::before{
    display: block; 
    content: ""; 
    margin-top: -80px; 
    height: 80px; 
    visibility: hidden; 
    pointer-events: none;
  }
  ...
}
3 của vị trí
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
5 chúng ta muốn scroll tới. Dựa vào đây chúng ta sẽ cho window scroll tới vị trí của
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
5 nhưng scroll lùi một đoạn bằng chiều cao của
<header>
    ...
        <a href="#goto">Jumpa>
    ...
header>

<section class="section">
  <span id="section-1"> span>
  <h2>Section 1h2>
    ...
section>
0. Hãy cùng xem:

Trước tiên là jQuery Method:

$('a').click(function(e) {
  const headerHeight = $('header').height();
  const hash = this.hash;
  const scrollToSection = $(hash).offset().top - headerHeight;
  $('html, body').animate({
    scrollTop: scrollToSection,
  }, 300);
});

Đối với Javascript Method:

const navLink = document.querySelectorAll('a');
const header = document.querySelector('header');

for(let link of navLink){
  link.onclick = function(e) {
    e.preventDefault();
    const hash = link.hash;
    const section = document.querySelector(hash);
    const scrollToSection = section.offsetTop - header.offsetHeight;
    window.location.hash = hash;
    window.scrollTo(0, scrollToSection);
  }
}

Và đây là kết quả chúng ta đạt được

Lời kết

Trên đây chúng ta đã tìm hiểu 2 hướng xử lý khi muốn tạo một fixed header có chứa các thẻ link tới các khu vực trong page mà không khiến nội dung của các phần đó bị header che mất.

Nếu bài viết có sai sót ở đâu đó hoặc mọi người có cách xử lý hay hơn thì hãy để lại comment bên dưới. Cảm ơn mọi người đã đọc bài viết.

References

https://css-tricks.com/hash-tag-links-padding/

https://css-tricks.com/almanac/properties/s/scroll-padding/