Lập trình CSS - Đưa ngôn ngữ lập trình vào CSS (Phần 2)

T.V.T Marine Automation Company Limited, Vũ Thành Luân

Phần 1, tôi đã giới thiệu cho các bạn sơ lược về LESS và một số tính năng cơ bản của nó.

Trong bài này, tôi tiếp tục giới thiệu cho các bạn thêm một số tinh năng nâng cao, rất hữu ích khi chúng ta tiến hành làm việc với LESS. Chúng ta cùng bắt đầu nào!

Debug

Với bất cứ ngôn ngữ lập trình nào, khi mới bắt đầu làm quen, việc xảy ra lỗi là điều hoàn toàn bình thường, nhưng gặp lỗi mà không biết xử lý như thế nào thì thật là một trở ngại lớn cho những người mới bắt đầu.

Hiểu được điều này, less cung cấp cho chúng ta một chức năng debug khá hiệu quả.

Chúng ta cần thêm một thẻ script có nội dung như sau để thực hiện cấu hình less theo yêu cầu vào phía trước file less-1.4.1.min.js như ở phần 1 tôi đã nhắc tới.

<script type="text/javascript">
            less = {
                env: "development", // or "production"
                async: false,
                fileAsync: false,
                poll: 1000,
                functions: {},
                dumpLineNumbers: "all", // or "mediaQuery" or "all" or "comments"
            };
</script>

Trong đó:

  • env : khai báo môi trường phát triển, nếu website đang trong quá trình thiết kế, bạn hãy set là development, còn nếu như website đã đưa vào hoạt động ổn định, chúng ta nên set lại là production. Điều này rất hữu ích, nó góp phần giúp đỡ rất nhiều cho người lập trình, thông báo lỗi chi tiết khi ở chế độ development và bảo mật hơn khi ở chế độ production.
  • async: chế độ không đồng bộ javascript. Mắc định là false.
  • fileAsync: chế độ không đồng bộ trong giao thức truyền file, mặc đinh là false.
  • poll: khoảng thời gian tính bằng ms giữa 2 lần kiểm tra sự thay đổi.Nó được sử dụng ở chế độ watch mode. Đây là chế độ cho phép người dùng có thể thấy được sự thay đổi của less trực tiếp trên trình duyệt.Less sẽ tự động refresh css sau khoảng thời gian được cấu hình.(*)
  • functions: đây là nơi khai báo các hàm thêm để tương tác với less
  • dumpLineNumbers: đây chính là chế độ debug mà tôi đã nói ở trên. Trong thuộc tính này, chúng ta có 3 giá trị.

    all: hiển thị toàn bộ thông báo trong thẻ <style>
    mediaQuery: hiển thị mặc định với css đơn thuần.
    comments: hiển thị thêm comment về số dòng của từng câu less

(*) Chế độ watch mode. Để bật chế độ này chúng ta thực hiện chạy lệnh sau: less.watch();

Lệnh này có thể chạy trực tiếp trên trình duyệt hoặc trong mã javascript. Sau khi chạy lệnh này thành công. Khi nào bạn chỉnh sửa file styles.less thì lập tức, sự thay đổi đó sẽ có hiệu lực ngay trên website.
Ngoài ra, less còn cung cấp cho chúng ta chức năng debug ngay trên url. Thay vì bạn phải chính sửa option trong thẻ script, chúng ta chỉ cần thêm !dumpLineNumbers:mediaQuery vào trên url. Rất tiện phải không nào.

Hàm điều kiện

Less cung cấp cho chúng ta cách viết hàm rất linh hoạt, tùy theo điều kiện biến truyền vào mà sẽ thực thi những hàm khác nhau.

Dưới đây là một ví dụ:

.mixin (dark; @color) {  color: darken(@color, 10%);}
.mixin (light; @color) {
  color: lighten(@color, 10%);
}
.mixin (@_; @color) {
  display: block;
}


Vậy khi chúng ta chạy lệnh sau:

@switch: light;

.class {  .mixin(@switch; #888);}

Chúng ta sẽ nhận được:

.class {
  color: #a2a2a2;
  display: block;
}

Vì giá trị của biến @switchlight nên less sẽ thực thi hàm mixin thứ 2, Đồng thời hàm mixin thứ 3 cũng hoạt động vì nó nhận bất kỳ giá trị nào.

Chúng ta còn có thể sử dụng điều kiện when trong Less.

.mixin (@a) when (lightness(@a) >= 50%) {
  background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
  background-color: white;
}
.mixin (@a) {
  color: @a;
}

Nếu điều kiện thỏa mãn, hàm tương ứng sẽ được thực thi.

Ví dụ:

.class1 { .mixin(#ddd) }
.class2 { .mixin(#555) }

Kết quả trả về:

.class1 {
  background-color: black;
  color: #ddd;
}
.class2 {
  background-color: white;
  color: #555;
}

Các toán tử so sánh được sử dụng: >, >=, <, <=, =

Với từ khóa true, hai hàm dưới đây là như nhau

.truth (@a) when (@a) { ... }
.truth (@a) when (@a = true) { ... }

Nếu bạn sử dụng một giá trị khác từ khóa true, thì chúng đều có giá trị là false.

.class {
  .truth(40);
}

Bạn cũng có thể sử dụng nhiều biểu thức so sánh trong when bằng cách ngăn cách các biểu thức bằng dấu (,). Hàm sẽ được thực thi nếu một trong các biểu thức này đúng, nó tương tự như OR trong lập trình.

.mixin (@a) when (@a > 10), (@a < -10) { ... }

Và nếu bạn muốn sử dụng điều kiện AND:

.mixin (@a) when (isnumber(@a)) and (@a > 0) { ... }

Và tất nhiên không thể thiếu NOT

.mixin (@b) when not (@b > 0) { ... }

Ngoài ra, chúng ta cũng có thể sử dụng các biến của hàm để đưa vào biểu thức so sánh.

@media: mobile;

.mixin (@a) when (@media = mobile) { ... }
.mixin (@a) when (@media = desktop) { ... }

.max (@a; @b) when (@a > @b) { width: @a }
.max (@a; @b) when (@a < @b) { width: @b }

Để hỗ trợ tốt hơn trong hàm điều kiện, Less cung cấp cho chúng ta một số hàm kiểm tra loại dữ liệu

  • iscolor
  • isnumber
  • isstring
  • iskeyword
  • isurl

Và các hàm kiểm tra đơn vị.

  • ispixel
  • ispercentage
  • isem
  • isunit

Ví dụ:

.mixin (@a; @b: 0) when (isnumber(@b)) { ... } .mixin (@a; @b: black) when (iscolor(@b)) { ... }

Kế thừa

Nhiều khi viết CSS, chúng ta thường phải khai báo thuộc tính cho một id, class kèm theo các id, class phụ thuộc khác, việc này khiến code css của chúng ta dài hơn, khó kiểm soát hơn. Bởi vậy, Less cung cấp cho chúng ta khả năng kế thừa lại các  thuộc tính css của các đối tượng mà chúng ta đã khai báo.

Đây là một ví dụ khi chúng ta viết CSS đơn thuần:

#header { color: black; }
#header .navigation {
  font-size: 12px;
}
#header .logo {
  width: 300px;
}
#header .logo:hover {
  text-decoration: none;
}

Và đây là cách khai báo tương tự trong less

#header {
  color: black;

  .navigation {
    font-size: 12px;
  }
  .logo {
    width: 300px;
    &:hover { text-decoration: none }
  }
}

Và đây là cách viết rút gọn

#header        { color: black;
  .navigation  { font-size: 12px }
  .logo        { width: 300px;
    &:hover    { text-decoration: none }
  }
}

Bạn có thấy rằng chúng rất ngắn và dễ hiểu phải không nào.

Vậy trường hợp một bạn muốn khai báo css cho một class và các class phụ thuộc nhưng cũng muốn viết css cho đối tượng có cả 2 class thì làm thế nào?

.bordered {
  &.float {
    float: left;
  }
  .top {
    margin: 5px;
  }
}

Như trên ta có:

.bordered.float {
  float: left;
}
.bordered .top {
  margin: 5px;
}

Toán tử

Trong less, chúng ta hoàn toàn có thể sử dụng các phép tính để tính toán giá trị.

@base: 5%;
@filler: (@base * 2);
@other: (@base + @filler);

color: (#888 / 4);
background-color: (@base-color + #111);
height: (100% / 2 + @filler);

Nếu trong biểu thức tính, mà có chứa đơn vị, ví dụ như px, em thì less sẽ tự động sử dụng đơn vị đó cho kết quả cuối cùng.

@var: (1px + 5);

Trong ví dụ  trên, kết quả trả về của biến @var sẽ là 6px;

Vậy nếu trong phép tính, chúng ta sử dụng 2 đơn vị khác nhau thì sẽ như thế nào.

@var: (1px + 5em);

Kết quả trả về vẫn là 6px. Less sẽ lấy đơn vị đầu tiên mà nó gặp và gán vào giá trị trả về. Nếu bạn đảo ngược thứ tự thì kế quả trả về sẽ là 6em.

Namespaces

Ở trên tôi đã nói tới tính kế thừa của less, tuy nhiên, khi chúng ta nhóm chúng lại, vậy nếu muốn sử dụng một thuộc tính nào đó của nhóm đó, chúng ta phải làm thế nào. Để giải quyết vấn đề này, chúng ta cùng xem một ví dụ minh họa

#bundle {
  .button () {
    display: block;
    border: 1px solid black;
    background-color: grey;
    &:hover { background-color: white }
  }
  .tab { ... }
  .citation { ... }
}

Giờ chúng ta muốn sử dụng thuộc tính css của .button trong #bundle ta chỉ cần

#header a {
  color: orange;
  #bundle > .button;
}

Như vậy, tại phần 2 này, tôi đã giới thiệu cho các bạn thêm một số tính năng của less. Các bạn đã có thể tự thực hành để trải nghiệm less.

Bài tiếp theo, tôi sẽ đi sâu và khai thác các hàm mặc định mà less đã cung cấp. Mong rằng loạt bài viết này giúp ích cho bạn.

Mọi ý kiến đóng góp để bài viết hoàn thiện luôn được hoan nghênh, chúng tôi luôn mong đợi những ý kiến đóng góp từ các bạn. Cảm ơn và hẹn gặp lại!.