0

Làm thế nào để viết một ứng dụng Todo App với HTML và CSS mà không sử dụng JavaScript

Giới thiệu về Todo App

Đúng với cái tên của nó, Todo app là một ứng dụng cho phép bạn tạo ra các công việc bạn cần làm. Qua đó giúp cho bản thân chúng ta biết chính xác việc tiếp theo cần đạt được và cũng biết chính xác những việc mà mình đã hoàn thành tránh tình trạng bị mất phương hướng trong quá trình làm việc. Trong bài viết này, khác với việc sử dụng TodoMVC, trong phương pháp hoàn thành không sử dụng JavaScript, tất cả những tương tác đều hoạt động dựa trên CSS. Vậy cấu trúc của nó là gì? Nói một cách đơn giản, nó được thực hiện bằng cách kết hợp của HTML, selector (~) của CSS, CSS counter và các selector khác như :checked, :target, :required. Xem thử App Xem source code

Những việc có thể thực hiện được :

  • Thêm Todo(lớn nhất là 50 cái)
  • Xác nhận hoàn thành Todo
  • Xóa Todo
  • Filtering (hoàn thành, chưa hoàn thành)
  • Đếm số lượng các item còn sót lại
  • Không cho phép thêm các chuỗi rỗng

Những việc không thể làm được :

  • Duy trì trạng thái thêm vào sau khi load lại trang
  • Thêm Todo bằng phím Enter
  • Đánh dấu tất cả các Todo là done

Hiển thị, không hiển thị content bằng :checked

Một ứng dụng tương tác được tiến hành để lưu và thay đổi bên trong CSS. Thông thường, Trạng thái thì có trong HTML nhưng mà trong trường hợp không sử dụng JavaScript thì không thể thay đổi cấu trúc của DOM trong HTML được. Để có thể khắc phục được vấn đề này, ta sẽ sử dụng một checkbox để lưu trạng thái và một selector giả :checked để có thể truy cập vào trạng thái đó. Dưới đây là một ví dụ đơn giản :

Toggle content: <input type="checkbox"></input>
<div id="content">
  Hello world!
</div>

<style>
  #content {
    display: none;
  }
  input:checked ~ #content {
    display: block;
  }
</style>

Trong đoạn code này, chúng ta sử dụng "general sibling combinator" (~) selector của CSS. Với general sibling combinator, chúng ta có thể select các element cùng chung một anh em mà không cần xem thử chúng có kề sát hay không. Gỉa sử ta có A~B, selector này khớp tất cả các element B theo sau một element A, không cần biết có kề sát hay không. Trước khi tiếp tục chúng ta hãy cùng tìm hiểu thuộc tính for của thẻ label. Thẻ label định nghĩa nhãn cho thành phần input, nó không hiển thị bất cứ gì đặc biệt cho người dùng, tuy nhiên nó cung cấp một vài cải thiện cho người dùng sử dụng chuột, nếu click chuột vào nhãn, sẽ đưa đưa con trỏ chuột vào vùng <input/>. Và muốn sử dụng hiệu quả <label> cần thiết phải cho giá trị id của <input/> và giá trị for của <label> phải trùng nhau.

<input type="checkbox" id="toggle-box"></input>
<label for="toggle-box">Toggle!</label>
<div id="content">
  Hello world!
</div>

Áp dụng việc sử dụng Hiển thị/không hiển thị content vào mô hình

Và sau đây, khi mà đã hiểu được cơ bản phương pháp lưu trạng thái ở trên, chúng ta bắt đầu xây dựng Todo App nào. Mỗi Todo item sẽ mang 3 trạng thái checkbox :

  1. Todo đã được tạo ra?
  2. Todo đã được hoàn thành?
  3. Todo đã được xóa?

Mục 1 có lẽ là một phát hiện để biết được App này hoạt động như thế nào. Không có phương pháp nào để thay đổi DOM mà không sử dụng JavaScript . Nói cách khác, tất cả các Todo item đều phải được nhúng vào HTML trước. Chúng ta hãy nhìn thử vào source code của trang, có thể thấy được đã có 50 Todo item đã được thêm vào từ trước. Và CSS được sử dụng để hiển thị/ không hiển thị những Todo item đó. Cấu trúc của DOM được trình bày như sau. Todo item đầu tiên sẽ chứa các Todo item còn lại, Todo item thứ 2 sẽ chứa Todo item từ 3 đến 50 và cứ tiếp tục cho các Todo item tiếp theo.

.todo#todo-1
  input.created-checkbox
  .todo#todo-2
    input.created-checkbox
    .todo#todo-3
      …

Và đây là một phần screenshot của list Todo: Mỗi Todo item được thể hiện như sau: Và bây giờ chúng ta đi chi tiết đến việc xóa Todo item được thực hiện như thế nào. Trước hết, chúng ta sẽ sử dụng checkbox để lưu trạng thái của deleted.

<input type="checkbox" class="deleted-checkbox" id="deleted-checkbox-3">

Và để định nghĩa cho thành phần input này chúng ta sẽ tạo thêm một label sau :

<label for="deleted-checkbox-3" class="deleted-checkbox-label">×</label>

Khi mà checkbox được :checked thì các giá trị của mục này sẽ không được hiển thị. Tuy nhiên, với mỗi một Todo Item, thì đi theo nó sẽ bao gồm các Todo Item khác, nên để hiển thị những Todo item đó, chúng ta sẽ làm như sau :

.deleted-checkbox:checked ~ :not(.todo) {
  display: none !important;
}

Lọc Todo Item theo hoàn thành/chưa hoàn thành

Trong TodoMVC, sẽ có các tùy chọn chỉ hiển thị những item đã hoàn thành hoặc chưa hoàn thành. Bạn có thể thực hiện các chức năng bằng cách sử dụng checkbox, tuy nhiên để thực hiện nó một cách độc đáo hơn ta sẽ sử dụng một URL hash như sau: Link của Filter được thể hiện như sau:

<a class="filter-active" href="#/active">Active</a>

Khi mà click vào link thì trình duyệt sẽ di chuyển đến phần tử mà có ID là /active. Điểm quan trọng ở đây là phần tử đó có thể match với selector giả :target.

<div id="/completed" class="completed-filter">
  <!-- Todo items -->
</div>

Và chúng ta có thể làm ẩn đi các phần tử con đã được tạo ra nhưng chưa được đánh dấu là "hoàn thành".

.completed-filter:target
  .created-checkbox:checked
  ~ .done-checkbox:not(:checked)
  ~ .todo-input {
  display: none !important;![](https://images.viblo.asia/5e413e79-5040-44b7-aa38-f247cb3579c5.png)
}

Vì vậy, nhờ việc thêm vào checkbox mà chúng ta đã có thể truy cập, lưu các trạng thái ở bên trong URL.

Xử lý các Todo Item chưa hoàn thành

Như đã nói ở trên, chúng ta đã tạo sẵn 50 Todo item, tuy nhiên những Todo chưa được tạo thì ta sẽ cho ẩn đi và sử dụng thuộc tính position:absolute để cho lên đầu của list Todo và thêm button [Add] để có thể thêm được Todo.

Đếm số lượng các Item còn lại

CSS có một chức năng tuyệt vời đó chính là Counters. Chức năng này sẽ đếm cho chúng ta biết có bao nhiêu item ở trong CSS Seletor. Chúng ta sẽ sử dụng nó để hiển thị xem còn sót lại bao nhiêu Todo item còn chưa hoàn thành. Chức năng counters được mô tả như sau:

body {
  counter-reset: items-left;
}

.created-checkbox:checked
  ~ .deleted-checkbox:not(:checked)
  ~ .done-checkbox:not(:checked)
  ~ .items-left-counter-helper {
  counter-increment: items-left;
}

#items-left:before {
  content: counter(items-left);
}

Dưới đây là những item mà chúng ta cần đếm:

  1. Item đã tạo hoàn thành
  2. Item chưa được xóa
  3. Item chưa hoàn thành

Chúng ta sẽ sử dụng .mark-undone-checkbox-label thay vì sử dụng .items- left-counter-helper . CSS counter sẽ không hỗ trợ đếm các phần tử đang bị ẩn đi. Vì vậy, khi chuyển sang filter "Completed" thì giá trị items left sẽ bằng 0 (bởi vì các item chưa hoàn thành đều được ẩn đi).

Làm sao để không thể tạo các Todo Item trống

Để làm được việc này, chúng ta sẽ sử dụng selector giả :required. Ở trong HTML đã có sẵn những chức năng validation của form. Bằng cách sử dụng này, chúng ra có thể rằng buộc điều kiện cho các text form.

<input required type="text" value="" class="todo-input">

Hơn nữa, chúng ta sẽ sử dụng thêm CSS để kiểm tra các giá trị nhập vào field có thể thêm được hay không?

input:not(:valid) ~ .created-checkbox-label {
  pointer-events: none;
}

Bằng việc sử dụng pointer-events, chúng ta có thể vô hiệu hóa các thao tác xử lý chuột như là click hay hover.

Bạn có thể thêm một Todo Item bằng phím Enter

Để thực hiện công việc này trên TodoMVC là một điều dễ dàng, tuy nhiên nếu không sử dụng JavaScript là một điều rất khó. Và thay vào đó, sẽ sử dụng một button [Add] để thực hiện công việc này.

Kết thúc

Qua bài viết này, chúng ta đã có thể biết thêm được cách làm thế nào chỉ cần sử dụng HTML và CSS để viết ra một ứng dụng Todo App rồi đúng không nào. Điều quan trọng ở đây là chúng ta có thể hiểu sâu sắc hơn và sẽ cảm thấy thú vị hơn về các chức năng mà CSS mang lại. Hi vọng bài viết sẽ có giúp ích cho mọi người.

Nguồn tham khảo

https://frasco.io/how-to-write-a-javascript-free-todo-app-using-just-html-and-css-c2356069e9d1


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.