Tối ưu cách viết CSS

CSS có thể làm cho một trang web HTML nhàm chán thành các trang web sinh động, nhưng việc sử dụng CSS không đúng cách cũng có thể khiến trang web của bạn gặp vấn đề ngay trước cả khi trang web của bạn được render. Ngoài tối ưu thuật toán, xử lý ở phần controller, model hoặc cơ sở dữ liệu thì CSS cũng cần được tối ưu hóa để giúp trang web chạy nhanh hơn.
Chính vì vậy, bài viết này sẽ đưa tới cho bạn các tips để tối ưu hóa CSS một cách hiệu quả.

Basic

CSS không phải nguyên nhân trực tiếp gây ra vấn đề khi load trang web, nhưng bạn vẫn nên tối ưu những phần nặng của dữ liệu mà CSS có thể chứa như: Xử dung CDN, xoá các tệp không xử dụng đến, thay đổi kích thước hình ảnh, xử dụng thumbnail, giảm thiểu số file css nếu có thể,…

Tuân thủ một số quy tắc trong style coding conventions cũng là một điều nên nhớ, dưới đây là một số quy tắc bạn có thể tham khảo:

  • Lùi vào 2 space (khoảng trống) cho mỗi thuộc tính
  • Sử dụng ngoặc kép thay vì sử dụng ngoặc đơn (font-family: “Arial Black”, input[type=”checkbox”])
  • Đặt một dấu cách ở đằng sau dấu :
  • Đặt một dấu cách ở trước dấu {
  • Kết thúc định nghĩa các thuộc tính bằng một dấu chấm phẩy (mặc dù việc thêm dấu chấm phẩy là không bắt buộc nhé)
  • Sử dụng các cú pháp ngắn gọn nếu có thể ví dụ như (padding, margin…)
  • Chỉ khai báo mỗi dòng một thuộc tính (dễ nhìn, nếu lỗi có thể biết lỗi được ở dòng nào thuộc tính nào)
  • Code thêm những thuộc tính khác mà trình duyệt này hỗ trợ mà trình duyệt khác không hỗ trợ
  • Giữa các khối CSS nên có một khoảng trắng
  • Khuyến khích sử dụng mã màu (#fff)
CSS Pre-Processors

CSS Pre-Processors là một ngôn ngữ tiền xử lý CSS, các bạn có thể hiểu nó là một kiểu viết mở rộng, nâng cấp hơn so với CSS. Mục đích của CSS Pre-Processors được sinh ra nhằm mục đích đưa các đoạn code CSS trở nên giống hơn một ngôn ngữ lập trình, và cách viết này sẽ biên dịch lại thành các đoạn code CSS bình thường.

Để áp dụng các CSS Pre-Processors vào dự án của bạn thì có vài công cụ nổi tiếng giúp các bạn áp dụng vào dự án như: SCSS, SASS, LESS, Stylus… Trong bài này mình sẽ giới thiệu về SCSS/SASS.

Tất nhiên là phải có những lợi ích nhất định của CSS Pre-Processors thì nó mới được áp dụng vào các dự án như:

  • Cải thiện thời gian viết CSS
  • Linh hoạt hơn và có khả năng sử dụng lại code
  • Dễ dàng bảo trì cũng như là phát triển
  • Cấu trúc viết code rõ ràng, dễ nhìn hơn rất nhiền
  • Hạn chế được những đoạn code trùng lặp, file code nhỏ gọn.
SASS

SASS là viết tắt của Syntactically Awesome StyleSheets là một CSS Pre-Processors nổi tiếng được biết đến trong giới Front-end Developer. SASS được sinh ra bởi lập trình viên Ruby, nếu như bạn đã làm việc với Ruby thì ắt hẳn sẽ biết tới các template phổ biến như HAML hay SLIM.

Tại sao mà mình lại nhắc đến Ruby, nó liên quan gì đến CSS thì mình xin giải thích đó chính là đến từ cú pháp. Ví dụ như khi viết SLIM các bạn sẽ không cần các dấu đóng thẻ, hay dấu chấm phẩy, hay nhận biết các thẻ con bằng cách lùi dòng vào… Điều này chính là những kiểu viết của SASS.

Ví dụ như thế này

.nav

  width: 100%

  height: 100%

  float: right

  p

    color: #e1e1e1

    font-size: 14px;
SCSS

Một phần không nhỏ developer không thích cách viết của SASS lắm vì nó mang lại cảm giác đọc hơi rối cả khó hiểu, có lẽ chính vì thế nên đã có sự nâng cấp tuyệt vời đến từ SCSS.

SCSS hay còn gọi là Sassy CSS, có cú pháp giống với CSS hơn là SASS giúp chúng ta tiếp cận dễ hơn rất nhiều. Hiểu đơn giản thì SCSS là một phiên bản nâng cấp của SASS.

.nav {

  width: 100%;

  height: 100%;

  float: right;

  p {

    color: #e1e1e1

    font-size: 14px;

  }

}
Sự khác biệt cơ bản của SCSS và SASS

Qua 2 phần giới thiệu ở trên thì phần nào các bạn cũng đã hiểu hiểu SCSS và SASS là gì và cách viết như thế nào. Ở phần này mình xin tóm tắt lại chút sự khác biệt để các bạn có cái nhìn tổng quát hơn.

SASS:

  • Cú pháp ngắn gọn hơn
  • Sử dụng indent để thể hiện quy tắc xếp chồng (nested rules)
  • Khi kết thúc một property thì không cần dấu ; để kết thúc
  • Khai báo mixins bằng ký tự =
  • Sử dụng mixins bằng ký tự +

SCSS

  • Cú pháp gần với CSS hơn
  • Sử dụng cặp dấu {} để thể hiện quy tắc xếp chồng
  • Kết thúc 1 khai báo property CSS bằng dấu ;
  • Khai báo mixins bằng cú pháp @mixins ten-mixins
  • Sử dụng mixins bằng cú pháp @include ten-mixins
Sử dụng variables

Bây giờ mình bắt đầu giới thiệu những thứ hay ho để giúp bạn viết CSS chuyên nghiệp hơn, hay ho hơn.

Để bắt đầu thì mình xin giới thiệu về variables. Đến CSS mà còn có cả variables (biến) thì cũng hơi bị thú vị rồi đấy.

Giả sử như dự án của bạn dùng đến cả trăm chỗ có thể sử dụng cùng một giá trị màu chả hạn, đối với các mã màu đơn giản thì các bạn nhớ được thôi chứ ví dụ có những mà màu rắc rối giả sử như DEFQ13 chả hạn, thì nhớ làm sao được, nhà còn bao việc 😄

Để tối ưu hơn trong việc này chúng ta sẽ đặt cái mã màu này trong một biến, giúp chúng ta thuận tiện sử dụng hơn nhiều.

$text-grey: #e1e1e1;

/* Sử dụng */

p {

  color: $text-grey;

}

div.container a {

  color: $text-grey;

}

Viết đơn giản không phải cầu kì.

Mixins

Mình từng nói ở trên là CSS Pre-Processors giúp chúng ta có thể tái sử dụng code. Mixins chính là cách để giúp chúng ta có thể làm được việc này một cách đơn giản.

@mixin bordered {

  border: 1px solid #ddd;
  
  &:hover {
  
  border-color: #999;
  
  }

}

/*Sử dụng chỉ cần include mixins đã khai báo*/

div {

    @include bordered;

}

Thậm chí chúng ta có thể truyền cả tham số vào mixins.

@mixin bordered($width) {

  border: $width solid #ddd;
  
  &:hover {
  
    border-color: #999;
    
  }
  
}

/*Sử dụng chỉ cần include mixins đã khai báo*/

div {
  @include bordered(1px);
}
Nested

Khi mà mới học lập trình HTML, CSS thì mình đã từng thế này, và mình nghĩ cũng nhiều bạn đã từng như mình.

<div class="container">

    <ul class="nav">

        <li class="item">

            <a class="item-children">Hello</a>

        </li>

    </ul>

</div>

Xong khi viết CSS sẽ dạng dạng như thế này.

.container {

  width: 100%;

}

.container .nav {

  font-size: 14px;

}

.container .nav .item {

  float: left;

}

.container .nav .item .children {

  texx-decoration: none

}

Nhìn đoạn code trên có khiếp không, lặp đi lặp lại các selector, đó là chỉ với trường hợp mình có 4 item con con bên trong. Chả lẽ giờ có đến chục item con con bên trong các bạn cũng viết kiểu như thế này thì rõ ràng là không hề ổn chút nào. Lúc người khác đọc lại code phải dò dò xem đâu là cha của nó các kiểu con đà điểu thì sẽ rất mất thời gian.

Nếu như ai còn đang viết kiểu như thế mình khuyên nên bỏ đi và áp dụng ngay kiểu nested rules như sau đây.

.container {

    width: 100%;

    .nav {

        font-size: 14px;

        .item {

            float: left;

            .children {

                text-decoration: none;

            }

        }

    }

}

Nhìn trông code có phải gọn gàng, dễ quản lí và chuyên nghiệp hơn chút rồi đấy. Hãy áp dụng nhé các bạn.

Ngoài ra còn rất nhiều các tính năng khác mà các bạn có thể lên trang chủ của nó tìm đọc nếu muốn.

Kĩ thuật OOCSS

OOCSS là viết tắt của Object-Oriented CSS, hướng đối tượng trong CSS. Cụ thể mà tính chất hướng đối tượng này đó là tính kế thừa.

Kĩ thuật này được sinh ra nhằm hạn chế việc trùng lặp code.

Khai báo class bổ trợ.

Nếu bạn nào đã sử dụng Bootstrap thì đây chính là kinh nghiệm khá hay mà chúng ta có thể học hỏi từ Bootstrap.

Viết cs ngắn gọn

<!DOCTYPE html>

<html>

  <head>
  
    <style>
    
    body {
      /* Thay vì viết từng thuộc tính */
    
      font-style: italic;
    
      font-weight: bold;
    
      font-size: .8em;
    
      line-height: 1.2;
    
      font-family: Arial, sans-serif;
    
      background-image: url("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSjnIfv9UzLhhQwAG_0mxil1Z5KyQT7xROTYA&usqp=CAU");
  
      background-repeat: no-repeat;
  
      background-position: center center;
  
      background-attachment: fixed;
    
      background-color: #fff;
      /* thì chúng ta có thể viết gọn lại như sau */
  
      font: italic bold .8em/1.2 Arial, sans-serif;
    
      background: #fff url("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSjnIfv9UzLhhQwAG_0mxil1Z5KyQT7xROTYA&usqp=CAU") no-repeat fixed center center;
    
    }
    
    h1 {
    
      color: green;
    
      text-align: center;
    
    }
    
    p {
    
      font-family: verdana;
    
      font-size: 20px;
    
      position: fixed;
    
      bottom: 0;
    
      text-align: center;
    
      width: 100%;
    
    }
    
    </style>
  
  </head>

  <body>
  
    <h1>Welcome to</h1>
    
    <p>All Rights Reserved</p>
  
  </body>

</html>

Lưu ý & suy ngẫm

Một selector với trọng số lớn liệu có tốt không?

Ví dụ:

/* Trọng số là 2,3,4 */

#main article.sports table#stats tr:nth-child(even) td:last-child {

  ...

}

Với trọng số là 2,3,4, bạn sẽ rất khó để override nó, và sẽ làm cho code của bạn rối rắm và khó để maintain hay extend.

Bất kì khi nào bạn rơi vào tình huống không hiểu vì sao element của mình lại có style không như mong muốn, thì Specificity sẽ giúp bạn. Tuy nhiên thay vì ngồi đếm trọng số bằng tay, giờ đây với công cụ devtools mạnh mẽ của các browser thì việc xác định lỗi style là vô cùng đơn giản. Tuy nhiên các công cụ này cũng xây dựng trên nguyên lý CSS Specificity mà thôi chứ không có gì khác biệt đâu. Bạn có thể tham khảo hình ảnh bên dưới để hiểu hơn về cách đánh trọng số.

Specificity chỉ có ý nghĩa nếu một element có nhiều selector cùng trỏ (target) đến nó. Nói nôm na là nếu cuộc chiến mà chỉ có 1 người tham gia thì hiển nhiên người đó thắng rồi.

Trong CSS có việc kế thừa style từ các element cha. Tuy nhiên việc kế thừa này sẽ luôn xếp sau những selector trỏ (target) đích danh đến element nhé. Bạn để ý khi sử dụng devtools là thấy thôi.

Việc có nên sử dụng inline styles không vẫn là một vấn đề gây tranh cãi. Một số linter sẽ warning nếu bạn viết inline styles, nhưng bạn vẫn có thể tắt warning đó đi nếu muốn. Một trong những lý do là vì trọng số của nó quá cao sẽ dễ gây ra các lỗi không mong muốn, hoặc sẽ rất khó để override và buộc phải dùng đến !important. Một lý do khác nữa là với nhiều “chuyên gia” thì CSS nên đặt trong các file .css để dễ quản lý, chứ nếu nằm trong style (html) thì rối loạn lên hết?

Mặc dù trùm cuối !important vô cùng mạnh mẽ, việc dùng đến !important không phải là một giải pháp tốt và cần hạn chế sử dụng, giống như inline styles mà mình vừa đề cập đến. Trước khi buộc phải dùng đến !important, bạn hãy suy xét cẩn thận xem chúng ta có thể sử dụng CSS Specificity để đạt được mục đích hay không.

BEM

Đây là một kĩ thuật để đặt tên cho class trong HTML/CSS. Cách đặt tên class với BEM sẽ làm code của chúng ta nhìn rất chuyên nghiệp và có logic hơn rất nhiều.

Việc áp dụng kĩ thuật này vào trong project sẽ giúp chúng ta dễ dàng maintain và phát triển, dễ dàng hơn với những người vào dự án sau này khi đọc lại code.

BEM là viết tắt của Block, Element và Modifier. Nguyên tắc để đặt tên class sẽ dựa trên 3 thành phần kia để chúng ta đặt tên class cho chuẩn chỉ.

Block: Một khối độc lập mang ý nghĩa riêng, mô tả rõ mục đích của nó. (header, container, menu…). Block sẽ chứa những định dạng chung để có thể tái sử dụng.

Element: Là một phần thuộc một khối và thực hiện một chức năng cụ thể, element này sẽ phụ thuộc vào block để đặt tên sao cho phải.

Modifier: Modifier sẽ dùng để thao tác nếu muốn thay đổi cách hiển thị của block hoặc element.

Ở đây mình không phải muốn giải thích hay giới thiệu chi tiết về 2 “phương pháp” này, mà chỉ muốn chỉ ra một vài điểm liên quan với Specificity thôi. Ngoài BEM và ITCSS ra còn có nhiều phương pháp khác nữa, nhưng cơ bản đều xây dựng trên Specificity cả.

BEM: mình mặc định bạn đã biết đến BEM, thì một vài tôn chỉ của nó có thể kể đến như:

Tránh sử dụng id (#foo): lý do thì như mình đã chia sẻ, id có trọng số lớn và khá khó để override, nên việc cố gắng override nó sẽ dễ đẩy CSS của bạn đến một tương lai không mấy sáng sủa.

Tránh nested selector, cố gắng làm phẳng selector: cũng cùng lý do, nested selector cũng làm tăng trọng số của selector.

Ví dụ BEM sẽ khuyến khích:

/* BEM thích điều này, trọng số chỉ là 0,1,0 nhưng vẫn rất specific

và khó bị conflict */



.block {}

.block__elem1 {}

.block__elem2 {}

.block__elem3 {}

/* Trọng số sẽ là 0,2,0, cũng không quá tệ, nhưng BEM không khuyến khích

và nó cũng rất dễ bị conflict. */

.block {}

.block .elem1 {}

.block .elem2 {}

.block .elem3 {}
Tổng kết

Trên đây là một số kiến thức nhỏ mình đã tìm hiểu được, hi vọng nó sẽ giúp ích cho bạn trong dự án.

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like