1 điểm bởi GN⁺ 2 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Khi chuyển một vài website từ Tailwind sang HTML ngữ nghĩa và CSS thuần, tác giả tự tái hiện chỉ những quy ước thật sự cần từ Tailwind
  • Vẫn giữ các hệ thống quen thuộc như preflight reset, bảng màu và font scale của Tailwind, nhưng chuyển chúng sang CSS thuần bằng CSS variables và tách file
  • Phần lớn CSS được chia thành các file theo từng component với class riêng, giúp giảm khả năng việc sửa một component vô tình làm hỏng component khác
  • Lý do rời Tailwind gồm sự phụ thuộc vào build system ở các phiên bản mới, file tailwind.min.css 2.8MB, việc trộn lẫn với CSS thuần và những giới hạn của CSS theo kiểu Tailwind
  • Về thiết kế responsive, tác giả muốn tận dụng CSS grid với auto-fit, grid-template-areas nhiều hơn là breakpoint, đồng thời xem @layer, @scope và container queries là các chủ đề cần học

Chuyển cấu trúc đã học từ Tailwind sang CSS thuần

  • Khi lần đầu dùng Tailwind cách đây 8 năm, tác giả chưa biết phải cấu trúc mã CSS như thế nào, và Tailwind rõ ràng là lựa chọn tốt hơn nhiều so với sự hỗn loạn hoàn toàn
  • Gần đây, trong khoảng một tuần, khi chuyển vài website từ Tailwind sang HTML ngữ nghĩa + CSS thuần, tác giả đã tự chọn và tái hiện những phần quy ước cần thiết mà Tailwind từng cung cấp
  • Sau khi đọc A whole cascade of layersHow I write CSS in 2024, tác giả nhận ra rõ ràng rằng mọi codebase CSS đều cần một hệ thống để quản lý các mối quan tâm khác nhau như layout, font, màu sắc và các component dùng chung
  • Tailwind vốn đã có sẵn các hệ thống như reset stylesheet, bảng màufont scale, nên những phần quen thuộc và hữu ích đó hoàn toàn có thể được mô phỏng lại trong CSS thuần

Các hệ thống chính được đặt trong codebase CSS

  • reset

    • Tác giả ban đầu sao chép khoảng 200 dòng preflight styles của Tailwind từ tailwind.css để dùng
    • Vì đã quen với reset của Tailwind từ lâu, quy tắc áp dụng box-sizing: border-box cho mọi phần tử giúp chiều rộng phần tử bao gồm cả padding
      * { box-sizing: border-box; }
    
    • Có thể tác giả còn đang vô thức phụ thuộc vào các quy tắc reset khác như html {line-height: 1.5;}, và nếu viết CSS mà không có các quy tắc đó thì có vẻ sẽ cần một giai đoạn thích nghi khá lớn
  • components

    • Phần lớn CSS được sắp xếp vào các file theo từng component, theo cách khá giống với component trong Vue hay React
    • Mỗi component có class riêng để CSS của component này không ghi đè lên CSS của component khác
    • Trên thực tế, khoảng 80% CSS cần chỉnh sửa nằm trong các file component, nên khi sửa một component dài 100 dòng thì chỉ cần nghĩ về đúng 100 dòng đó
    • Ví dụ, component .zine có thể có HTML như sau
      <figure class="zine horizontal">
          <img src="whatever.jpg">
      </figure>
    
    • CSS gom các trạng thái như .horizontal, .vertical, :hover vào bên trong component bằng selector lồng nhau
      .zine {
        ...
        &.horizontal {
          ...
        }
        &.vertical {
          ...
        }
        &:hover {
          ...
        }
      }
    
    • Dù chưa dùng cách ngăn can nhiễu giữa các component bằng cơ chế lập trình như Web Components hay @scope, chỉ riêng việc đặt ra và tuân thủ quy ước cũng đã mang lại cảm giác cải thiện rất nhiều
  • colours

    • colours.css gom các CSS variable có thể dùng khi cần
    • Vì màu sắc là phần khó và tác giả không muốn phải xem lại toàn bộ cách dùng màu trong lần refactor này, nên cách làm cũ vẫn được giữ nguyên
    • Quy tắc duy nhất là liệt kê toàn bộ màu được dùng trên website trong file này
      :root {
        --pink: #fea0c2;
        --pink-light: #F9B9B9;
        --red: #f91a55;
        --orange: rgb(222, 117, 31);
        ...
      }
    
  • font sizes

    • Trong Tailwind, chỉ cần chọn một nấc kích thước như text-lg, xl, 2xl, nên không cần phải nhớ đang dùng em, px hay rem
    • Để giữ điều này trong CSS thuần, tác giả định nghĩa các biến kích thước lấy từ Tailwind
      --size-xs: 0.75rem;
        --line-height-xs: 1rem;
    
        --size-sm: 0.875rem;
        --line-height-sm: 1.25rem;
    
    • Kích thước font được chỉ định bằng biến; cách này dài dòng hơn Tailwind một chút nhưng hiện tại vẫn là phương pháp khiến tác giả hài lòng
      h3 {
        font-size: var(--size-lg);
        line-weight: var(--line-weight-lg);
      }
    
  • utilities

    • Những phần tử lặp lại ở nhiều component, chẳng hạn như button, được xếp vào nhóm utilities
    • Một số utility class như .sr-only dành cho các phần tử chỉ nên hiển thị với người dùng screen reader được sao chép từ Tailwind
    • Tác giả muốn giữ khu vực này nhỏ gọn và cẩn thận mỗi khi thay đổi
  • base

    • Style “base” là các style được áp dụng trực tiếp trên toàn bộ website
    • Vì tác giả chưa đủ chắc chắn để áp nhiều style lên toàn site, phần này được giữ rất nhỏ
    • Hiện tại chỉ có hai quy tắc mà tác giả thấy ổn là cho <section>a, trong đó quy tắc cho <section> có thể còn thay đổi về sau
      /* put a 950px column in the middle of each <section> */
      section {
        --inner-width: 950px;
        padding: 3rem max(1rem, (100% - var(--inner-width))/2);
      }
    
      a {
        color: var(--orange);
      }
    
    • Với base style, có vẻ dễ nhất là gần như để trống lúc đầu, rồi khi thấy điều gì thực sự muốn dùng chung thì chuyển dần từ component lên base theo cách tiếp cận từ dưới lên
  • spacing

    • Cách quản lý padding và margin vẫn chưa được chốt hoàn toàn
    • Khi còn dùng Tailwind, tác giả thường thêm padding và margin khá ngẫu hứng ở nhiều chỗ cho đến khi giao diện trông đúng ý, còn bây giờ đang tìm một cách có nguyên tắc hơn
    • Hiện tại, tác giả cố gắng để các component layout bên ngoài chịu trách nhiệm về khoảng cách nếu có thể
    • Khi muốn tạo khoảng cách đều giữa các phần tử con trong một <section> có nhiều con, có thể dùng quy tắc sau
      section > *+* {
        margin-top: 1rem;
      }
    
  • responsive design

    • Trong Tailwind, tác giả dùng nhiều cú pháp dựa trên media query như md:text-xl để áp dụng style text-xl từ một kích thước màn hình trở lên
    • Hiện tại, tác giả muốn tạo các layout CSS grid linh hoạt hơn để không cần dùng breakpoint quá nhiều
    • Khi dùng auto-fit, có thể tự động hiển thị 2 cột trên màn hình lớn và 1 cột trên màn hình nhỏ
      display: grid;
        grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content));
        justify-content: center;
    
  • build system

    • Trong quá trình phát triển, không cần build system riêng
    • CSS có sẵn câu lệnh @import để tách và nhập file
      @import "reset.css";
      @import "typography.css";
      @import "colors.css";
    
    • CSS cũng hỗ trợ selector lồng nhau
      .page {
        h2 { ...}
      }
    
    • Nếu muốn gộp file CSS cho production thì có thể dùng esbuild
      esbuild style.css --bundle --loader:.svg=dataurl  --loader:.woff2=file --outfile=/tmp/out.css
    
    • Tác giả thường tránh dùng build system cho cả CSS lẫn JS, nhưng thấy esbuild chấp nhận được vì nó dựa trên web standard và là một binary Go tĩnh
    • Tác giả từng viết một bài về esbuild và Vue vào năm 2021

Vì sao rời khỏi Tailwind

  • Từ sau năm 2018, Tailwind ngày càng phụ thuộc mạnh vào build system, và phiên bản Tailwind mới nhất dường như không thể dùng nếu không có build system, nên tác giả đã dùng Tailwind v2 trong nhiều năm
  • Có vẻ như litewind là một lựa chọn thay thế để dùng Tailwind mà không cần build system
  • Tailwind vốn được giả định là sẽ dùng cùng build system, nhưng trên thực tế tác giả đã không làm vậy, nên nhiều dự án bị để lại file tailwind.min.css 2.8MB, tạo cảm giác khá gượng gạo
  • Kỹ năng CSS của tác giả hiện đã tốt hơn so với thời điểm mới bắt đầu dùng Tailwind
  • Cuối cùng thì Tailwind vẫn có những giới hạn, và khi muốn làm điều gì đó lạ hoặc đặc biệt trong CSS thì không phải lúc nào cũng làm được
  • Những giới hạn đó có thể rất hữu ích; thực tế trong lúc chuyển sang CSS thuần, tác giả vẫn tái hiện lại một số ràng buộc của Tailwind, nhưng giờ đây muốn chỉ chọn những ràng buộc thật sự cần thiết
  • Đã xuất hiện các website trong cùng một project trộn lẫn CSS thuần và Tailwind, và việc bảo trì chúng không hề dễ chịu
  • Tác giả cũng tò mò cảm giác sẽ như thế nào khi viết HTML mang tính ngữ nghĩa hơn

Những tính năng CSS muốn học tiếp

  • @layer là tính năng xử lý cascade layer; tác giả chưa dùng nhưng muốn học
  • @scope là tính năng khiến tác giả hứng thú trong việc xử lý style trong phạm vi component hay một vùng cụ thể
  • container queries là tính năng dành cho responsive design dựa trên container mà tác giả muốn tìm hiểu
  • subgrid là một tính năng liên quan đến CSS grid đang nằm trong danh sách quan tâm

Kết luận không phủ nhận hoàn toàn Tailwind

  • Dù hiện tại đang rời khỏi Tailwind, tác giả vẫn thấy hài lòng vì trước đây mình đã bắt đầu dùng Tailwind
  • Trong quá trình dùng Tailwind, tác giả đã học được rất nhiều, và ngay cả sau khi xóa tailwind.min.css, vẫn có thể tiếp tục dùng một phần Tailwind trong website
  • Những phần thú vị và đẹp mắt của CSS trên wizardzines.com được tạo nên nhờ Melody Starling, người đã thiết kế và viết CSS ban đầu cho website
  • Trong quá trình làm CSS, tác giả đã đọc rất nhiều bài viết từ CSS Tricks, Smashing Magazine và nhiều nơi khác, và cộng đồng CSS chia sẻ rất nhiều thực hành hữu ích nên đã giúp ích rất lớn

1 bình luận

 
Ý kiến trên Lobste.rs
  • Trong các dự án cá nhân, tôi hầu như không còn dùng framework CSS/JavaScript nữa
    Vì nếu không có phụ thuộc thì cũng không thể phát sinh lỗ hổng chuỗi cung ứng. Tất nhiên đó không phải là loại lỗ hổng duy nhất, nhưng như vậy cũng giúp ích

    • Tôi cũng quay lại khá nhiều với HTML/CSS/JS thuần, và chỉ thêm vào một chút những gì tự mình làm ra
      Đó là kết quả của việc mệt mỏi với framework, quá tải vì npm audit, và cả chuyện nhờ LLM mà tôi bớt bận tâm đến đánh giá của người khác về cách triển khai. Ví dụ như những câu hỏi kiểu “tại sao không dùng React và Tailwind?”
  • Đây đơn giản là cách CSS hoạt động
    Mỗi khi thấy ai đó mù quáng dùng Tailwind mà không biết điều này, tôi chỉ muốn ra ngoài gào lên với mây trời. Theo tôi, 90% của Tailwind chỉ là inline style với cú pháp khác đi, và có lẽ chỉ khá hơn thẻ <FONT> đúng một bậc

    • Tôi không rõ mục đích của bình luận này là gì, nhưng trong gần 8 năm dùng Tailwind, tôi đã thấy vô số bình luận kiểu hạ thấp người dùng Tailwind như thế này, và chưa cái nào giúp ích cho việc rời Tailwind hay nâng trình CSS cả
      Bài blog này giải thích đúng những gì mà bản thân tôi thực sự cần biết
    • Câu “90% của Tailwind chỉ là inline style với cú pháp khác đi” không thật sự chính xác
      Tailwind vận hành khá khác với inline style, và thực ra giống CSS hơn nhiều. Như bài viết cũng chỉ ra, phần lớn các thói quen tốt giúp dùng Tailwind hiệu quả cũng là những thói quen cần có để viết CSS hiệu quả. Tailwind gần với việc gắn một khối CSS có scope ngầm định vào mỗi phần tử, nhưng dùng một DSL riêng biệt
    • Biết CSS hoạt động thế nào và biết cách dùng nó hiệu quả là hai chuyện rất khác nhau
      Tôi hiểu rất rõ cơ chế hoạt động của CSS, nhưng CSS thuần vẫn khiến tôi thấy nặng nề, lại không giỏi thiết kế đồ họa nên tôi vẫn dùng Tailwind. Bài này mang lại những ý tưởng để cấu trúc CSS dựa trên nền tảng Tailwind
  • Với góc nhìn của một người không theo sát xu hướng gần đây, bài này dường như cho thấy khá rõ các thực hành CSS hiện đại
    Tôi cũng thích việc có nhiều liên kết dẫn tới những bài viết đã truyền cảm hứng cho tác giả. Có vẻ rất đáng đọc, dù hiện giờ tôi mới chỉ đọc "no outer margin"
    Tuy vậy, tôi hơi hoài nghi về cách tiếp cận thiết lập style mặc định theo kiểu “từ dưới lên”. Tôi cũng không biết nên làm cách nào khác, và nó có vẻ đáng để thử, nhưng style mặc định vốn dĩ luôn khá khó nhằn

  • Bài này thật sự rất hay
    Tôi cũng đã học CSS dần dần trong lúc làm đủ loại website nhỏ, và có lẽ sẽ hữu ích hơn nếu ngay từ đầu tôi suy nghĩ theo hướng có tính hệ thống như thế này. Tôi khá dị ứng với framework, nhưng vì không dùng chúng nên dù biết cách làm mọi thứ theo ý mình, tôi vẫn thường có cảm giác như đang lơ lửng trong khoảng không vô cấu trúc

  • Tôi thích ở chỗ bài này không nói kiểu “Tailwind dở lắm nên cứ dùng CSS đi”, mà là “Tailwind rất tuyệt, nhưng giờ có thể bạn không còn cần nó nữa
    Tôi luôn gặp khó khăn khi tự tay cấu trúc CSS, và nhờ bài này mà tôi bắt đầu suy nghĩ theo một hướng rất khác

  • Khi sắp xếp CSS, kỹ thuật cấu trúc này khá hữu ích với tôi: https://rstacruz.github.io/rscss/
    Nhìn chung nó rất khớp với những gì jvns mô tả trong bài gốc, đồng thời bổ sung thêm một chút cấu trúc và tính ngăn nắp lên trên đó